mirror of
https://github.com/inspircd/inspircd.git
synced 2025-03-10 19:19:02 -04:00
Merge branch 'insp3' into master.
This commit is contained in:
commit
cdab76406f
@ -303,7 +303,7 @@ class Packet final
|
||||
unsigned short Pack(unsigned char* output, unsigned short output_size)
|
||||
{
|
||||
if (output_size < HEADER_LENGTH)
|
||||
throw Exception("Unable to pack packet");
|
||||
throw Exception("Unable to pack oversized packet header");
|
||||
|
||||
unsigned short pos = 0;
|
||||
|
||||
@ -326,7 +326,8 @@ class Packet final
|
||||
if (q.type == QUERY_PTR)
|
||||
{
|
||||
irc::sockets::sockaddrs ip;
|
||||
irc::sockets::aptosa(q.name, 0, ip);
|
||||
if (!irc::sockets::aptosa(q.name, 0, ip))
|
||||
throw Exception("Unable to pack packet with malformed IP for PTR lookup");
|
||||
|
||||
if (q.name.find(':') != std::string::npos)
|
||||
{
|
||||
@ -357,7 +358,7 @@ class Packet final
|
||||
this->PackName(output, output_size, pos, q.name);
|
||||
|
||||
if (pos + 4 >= output_size)
|
||||
throw Exception("Unable to pack packet");
|
||||
throw Exception("Unable to pack oversized packet body");
|
||||
|
||||
short s = htons(q.type);
|
||||
memcpy(&output[pos], &s, 2);
|
||||
|
@ -28,19 +28,24 @@ namespace
|
||||
BoolExtItem* dl;
|
||||
}
|
||||
|
||||
/** Derived from Resolver, and performs user forward/reverse lookups.
|
||||
*/
|
||||
class UserResolver final
|
||||
class UserResolver
|
||||
: public DNS::Request
|
||||
{
|
||||
private:
|
||||
/** The socket address that the user we are looking up is connected from. */
|
||||
protected:
|
||||
// The socket address that the associated user was connected from at the time of lookup.
|
||||
const irc::sockets::sockaddrs sa;
|
||||
|
||||
/** UUID we are looking up */
|
||||
// The UUID of the user we are looking up the hostname of.
|
||||
const std::string uuid;
|
||||
|
||||
/** Handles errors which happen during DNS resolution. */
|
||||
UserResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& to_resolve, DNS::QueryType qt)
|
||||
: DNS::Request(mgr, me, to_resolve, qt)
|
||||
, sa(user->client_sa)
|
||||
, uuid(user->uuid)
|
||||
{
|
||||
}
|
||||
|
||||
// Handles errors which happen during DNS resolution.
|
||||
static void HandleError(LocalUser* user, const std::string& message)
|
||||
{
|
||||
user->WriteNotice("*** " + message + "; using your IP address (" + user->GetIPString() + ") instead.");
|
||||
@ -51,104 +56,138 @@ class UserResolver final
|
||||
dl->Unset(user);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Create a resolver.
|
||||
* @param mgr DNS Manager
|
||||
* @param me this module
|
||||
* @param user The user to begin lookup on
|
||||
* @param to_resolve The IP or host to resolve
|
||||
* @param qt The query type
|
||||
*/
|
||||
UserResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& to_resolve, DNS::QueryType qt)
|
||||
: DNS::Request(mgr, me, to_resolve, qt)
|
||||
, sa(user->client_sa)
|
||||
, uuid(user->uuid)
|
||||
/** Logs the result of a DNS lookup. */
|
||||
inline void LogLookup(const DNS::ResourceRecord& rr, bool cached) const
|
||||
{
|
||||
}
|
||||
|
||||
/** Called on successful lookup
|
||||
* if a previous result has already come back.
|
||||
* @param r The finished query
|
||||
*/
|
||||
void OnLookupComplete(const DNS::Query* r) override
|
||||
{
|
||||
LocalUser* bound_user = IS_LOCAL(ServerInstance->Users.FindUUID(uuid));
|
||||
if (!bound_user || bound_user->client_sa != sa)
|
||||
return;
|
||||
|
||||
const DNS::ResourceRecord* ans_record = r->FindAnswerOfType(this->question.type);
|
||||
if (!ans_record)
|
||||
{
|
||||
HandleError(bound_user, "Could not resolve your hostname: No " + this->manager->GetTypeStr(this->question.type) + " records found");
|
||||
return;
|
||||
}
|
||||
|
||||
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "DNS %s result for %s: '%s' -> '%s'%s",
|
||||
this->manager->GetTypeStr(question.type).c_str(), uuid.c_str(),
|
||||
ans_record->name.c_str(), ans_record->rdata.c_str(),
|
||||
r->cached ? " (cached)" : "");
|
||||
|
||||
if (this->question.type == DNS::QUERY_PTR)
|
||||
{
|
||||
const DNS::QueryType qt = bound_user->client_sa.family() == AF_INET6 ? DNS::QUERY_AAAA : DNS::QUERY_A;
|
||||
UserResolver* res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record->rdata, qt);
|
||||
try
|
||||
{
|
||||
this->manager->Process(res_forward);
|
||||
}
|
||||
catch (DNS::Exception& e)
|
||||
{
|
||||
delete res_forward;
|
||||
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason());
|
||||
|
||||
HandleError(bound_user, "There was an internal error resolving your host");
|
||||
}
|
||||
}
|
||||
else if (this->question.type == DNS::QUERY_A || this->question.type == DNS::QUERY_AAAA)
|
||||
{
|
||||
/* Both lookups completed */
|
||||
|
||||
irc::sockets::sockaddrs* user_ip = &bound_user->client_sa;
|
||||
bool rev_match = false;
|
||||
if (user_ip->family() == AF_INET6)
|
||||
{
|
||||
struct in6_addr res_bin;
|
||||
if (inet_pton(AF_INET6, ans_record->rdata.c_str(), &res_bin))
|
||||
{
|
||||
rev_match = !memcmp(&user_ip->in6.sin6_addr, &res_bin, sizeof(res_bin));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct in_addr res_bin;
|
||||
if (inet_pton(AF_INET, ans_record->rdata.c_str(), &res_bin))
|
||||
{
|
||||
rev_match = !memcmp(&user_ip->in4.sin_addr, &res_bin, sizeof(res_bin));
|
||||
}
|
||||
}
|
||||
|
||||
if (rev_match)
|
||||
{
|
||||
bound_user->WriteNotice("*** Found your hostname (" + this->question.name + (r->cached ? ") -- cached" : ")"));
|
||||
bool display_is_real = bound_user->GetDisplayedHost() == bound_user->GetRealHost();
|
||||
bound_user->ChangeRealHost(this->question.name, display_is_real);
|
||||
dl->Unset(bound_user);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleError(bound_user, "Your hostname does not match up with your IP address");
|
||||
}
|
||||
}
|
||||
manager->GetTypeStr(question.type).c_str(), uuid.c_str(), rr.name.c_str(),
|
||||
rr.rdata.c_str(), cached ? " (cached)" : "");
|
||||
}
|
||||
|
||||
/** Called on failed lookup
|
||||
* @param query The errored query
|
||||
*/
|
||||
public:
|
||||
void OnError(const DNS::Query* query) override
|
||||
{
|
||||
LocalUser* bound_user = IS_LOCAL(ServerInstance->Users.FindUUID(uuid));
|
||||
if (bound_user && bound_user->client_sa == sa)
|
||||
HandleError(bound_user, "Could not resolve your hostname: " + this->manager->GetErrorStr(query->error));
|
||||
LocalUser* user = IS_LOCAL(ServerInstance->Users.FindUUID(uuid));
|
||||
if (user && user->client_sa == sa)
|
||||
HandleError(user, "Could not resolve your hostname: " + this->manager->GetErrorStr(query->error));
|
||||
}
|
||||
};
|
||||
|
||||
// Handles checking the retrieved PTR record against its A/AAAA records.
|
||||
class UserIPResolver final
|
||||
: public UserResolver
|
||||
{
|
||||
public:
|
||||
UserIPResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& host)
|
||||
: UserResolver(mgr, me, user, host, user->client_sa.family() == AF_INET6 ? DNS::QUERY_AAAA : DNS::QUERY_A)
|
||||
{
|
||||
}
|
||||
|
||||
void OnLookupComplete(const DNS::Query* query) override
|
||||
{
|
||||
LocalUser* user = IS_LOCAL(ServerInstance->Users.FindUUID(uuid));
|
||||
if (!user || user->client_sa != sa)
|
||||
return;
|
||||
|
||||
bool hasrecord = false;
|
||||
bool matches = false;
|
||||
const DNS::QueryType qt = user->client_sa.family() == AF_INET6 ? DNS::QUERY_AAAA : DNS::QUERY_A;
|
||||
for (const auto& rr : query->answers)
|
||||
{
|
||||
if (rr.type != qt)
|
||||
continue;
|
||||
|
||||
// We've seen an A/AAAA record.
|
||||
hasrecord = true;
|
||||
|
||||
switch (user->client_sa.family())
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
// Does this result match the user's IPv4 address?
|
||||
struct in_addr v4addr;
|
||||
if (inet_pton(AF_INET, rr.rdata.c_str(), &v4addr) == 1)
|
||||
matches = !memcmp(&user->client_sa.in4.sin_addr, &v4addr, sizeof(v4addr));
|
||||
break;
|
||||
}
|
||||
|
||||
case AF_INET6:
|
||||
{
|
||||
// Does this result match the user's IPv6 address?
|
||||
struct in6_addr v6addr;
|
||||
if (inet_pton(AF_INET6, rr.rdata.c_str(), &v6addr) == 1)
|
||||
matches = !memcmp(&user->client_sa.in6.sin6_addr, &v6addr, sizeof(v6addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we've found a valid match then stop processing records.
|
||||
if (matches)
|
||||
{
|
||||
LogLookup(rr, query->cached);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
{
|
||||
// We have found the hostname for the user.
|
||||
user->WriteNotice("*** Found your hostname (" + this->question.name + (query->cached ? ") -- cached" : ")"));
|
||||
bool display_is_real = user->GetDisplayedHost() == user->GetRealHost();
|
||||
user->ChangeRealHost(this->question.name, display_is_real);
|
||||
dl->Unset(user);
|
||||
}
|
||||
else if (hasrecord)
|
||||
{
|
||||
// The hostname has A/AAAA records but none of them are the IP address of the user.
|
||||
HandleError(user, "Your hostname does not match up with your IP address");
|
||||
}
|
||||
else
|
||||
{
|
||||
// The hostname has no A/AAAA records.
|
||||
HandleError(user, "Could not resolve your hostname: No " + this->manager->GetTypeStr(this->question.type) + " records found");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handles retrieving the PTR record for users.
|
||||
class UserHostResolver final
|
||||
: public UserResolver
|
||||
{
|
||||
public:
|
||||
UserHostResolver(DNS::Manager* mgr, Module* me, LocalUser* user)
|
||||
: UserResolver(mgr, me, user, user->GetIPString(), DNS::QUERY_PTR)
|
||||
{
|
||||
}
|
||||
|
||||
void OnLookupComplete(const DNS::Query* query) override
|
||||
{
|
||||
LocalUser* user = IS_LOCAL(ServerInstance->Users.FindUUID(uuid));
|
||||
if (!user || user->client_sa != sa)
|
||||
return;
|
||||
|
||||
// An IP can have multiple PTR records but it is considered bad practise to have
|
||||
// more than one so to simplify the lookup logic we only use the first.
|
||||
const DNS::ResourceRecord* rr = query->FindAnswerOfType(DNS::QUERY_PTR);
|
||||
if (!rr)
|
||||
{
|
||||
HandleError(user, "Could not resolve your hostname: No " + this->manager->GetTypeStr(this->question.type) + " records found");
|
||||
return;
|
||||
}
|
||||
|
||||
LogLookup(*rr, query->cached);
|
||||
UserResolver* res_forward = new UserIPResolver(this->manager, this->creator, user, rr->rdata);
|
||||
try
|
||||
{
|
||||
this->manager->Process(res_forward);
|
||||
}
|
||||
catch (const DNS::Exception& e)
|
||||
{
|
||||
delete res_forward;
|
||||
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason());
|
||||
|
||||
HandleError(user, "There was an internal error resolving your host");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -181,7 +220,7 @@ class ModuleHostnameLookup final
|
||||
|
||||
user->WriteNotice("*** Looking up your hostname...");
|
||||
|
||||
UserResolver* res_reverse = new UserResolver(*this->DNS, this, user, user->GetIPString(), DNS::QUERY_PTR);
|
||||
UserResolver* res_reverse = new UserHostResolver(*this->DNS, this, user);
|
||||
try
|
||||
{
|
||||
/* If both the reverse and forward queries are cached, the user will be able to pass DNS completely
|
||||
|
@ -853,7 +853,7 @@ void ModuleSpanningTree::OnDecodeMetaData(Extensible* target, const std::string&
|
||||
// HACK: this should use automatically synced user metadata in v4.
|
||||
User* dest = static_cast<User*>(target);
|
||||
if (dest && (extname == "uniqueusername"))
|
||||
dest->uniqueusername = true;
|
||||
dest->uniqueusername = (extdata != "0");
|
||||
}
|
||||
|
||||
Cullable::Result ModuleSpanningTree::Cull()
|
||||
|
@ -113,6 +113,25 @@ SecurityIPResolver::SecurityIPResolver(Module* me, DNS::Manager* mgr, const std:
|
||||
{
|
||||
}
|
||||
|
||||
bool SecurityIPResolver::CheckIPv4()
|
||||
{
|
||||
// We only check IPv4 addresses if we have checked IPv6.
|
||||
if (query != DNS::QUERY_AAAA)
|
||||
return false;
|
||||
|
||||
SecurityIPResolver* res = new SecurityIPResolver(mine, this->manager, host, MyLink, DNS::QUERY_A);
|
||||
try
|
||||
{
|
||||
this->manager->Process(res);
|
||||
return true;
|
||||
}
|
||||
catch (const DNS::Exception&)
|
||||
{
|
||||
delete res;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SecurityIPResolver::OnLookupComplete(const DNS::Query *r)
|
||||
{
|
||||
for (std::shared_ptr<Link> L : Utils->LinkBlocks)
|
||||
@ -121,31 +140,27 @@ void SecurityIPResolver::OnLookupComplete(const DNS::Query *r)
|
||||
{
|
||||
for (const auto& ans_record : r->answers)
|
||||
{
|
||||
if (ans_record.type == this->question.type)
|
||||
Utils->ValidIPs.push_back(ans_record.rdata);
|
||||
if (ans_record.type != this->question.type)
|
||||
continue;
|
||||
|
||||
Utils->ValidIPs.push_back(ans_record.rdata);
|
||||
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Resolved '%s' as a valid IP address for link '%s'",
|
||||
ans_record.rdata.c_str(), MyLink->Name.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CheckIPv4();
|
||||
}
|
||||
|
||||
void SecurityIPResolver::OnError(const DNS::Query *r)
|
||||
{
|
||||
// This can be called because of us being unloaded but we don't have to do anything differently
|
||||
if (query == DNS::QUERY_AAAA)
|
||||
{
|
||||
SecurityIPResolver* res = new SecurityIPResolver(mine, this->manager, host, MyLink, DNS::QUERY_A);
|
||||
try
|
||||
{
|
||||
this->manager->Process(res);
|
||||
return;
|
||||
}
|
||||
catch (DNS::Exception &)
|
||||
{
|
||||
delete res;
|
||||
}
|
||||
}
|
||||
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Could not resolve IP associated with Link '%s': %s",
|
||||
if (CheckIPv4())
|
||||
return;
|
||||
|
||||
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Could not resolve IP associated with link '%s': %s",
|
||||
MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str());
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ class SecurityIPResolver final
|
||||
Module* mine;
|
||||
std::string host;
|
||||
DNS::QueryType query;
|
||||
bool CheckIPv4();
|
||||
public:
|
||||
SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, std::shared_ptr<Link> x, DNS::QueryType qt);
|
||||
void OnLookupComplete(const DNS::Query *r) override;
|
||||
|
@ -82,19 +82,43 @@ class CommandStartTLS final
|
||||
}
|
||||
};
|
||||
|
||||
class TLSCap final
|
||||
: public Cap::Capability
|
||||
{
|
||||
private:
|
||||
dynamic_reference_nocheck<IOHookProvider>& sslref;
|
||||
|
||||
bool OnList(LocalUser* user) override
|
||||
{
|
||||
return sslref;
|
||||
}
|
||||
|
||||
bool OnRequest(LocalUser* user, bool adding) override
|
||||
{
|
||||
return sslref;
|
||||
}
|
||||
|
||||
public:
|
||||
TLSCap(Module* mod, dynamic_reference_nocheck<IOHookProvider>& ssl)
|
||||
: Cap::Capability(mod, "tls")
|
||||
, sslref(ssl)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleStartTLS final
|
||||
: public Module
|
||||
{
|
||||
private:
|
||||
CommandStartTLS starttls;
|
||||
Cap::Capability tls;
|
||||
TLSCap tls;
|
||||
dynamic_reference_nocheck<IOHookProvider> ssl;
|
||||
|
||||
public:
|
||||
ModuleStartTLS()
|
||||
: Module(VF_VENDOR, "Provides the IRCv3 tls client capability.")
|
||||
, starttls(this, ssl)
|
||||
, tls(this, "tls")
|
||||
, tls(this, ssl)
|
||||
, ssl(this, "ssl")
|
||||
{
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user