summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/modules.h9
-rw-r--r--src/modules.cpp1
-rw-r--r--src/modules/m_dnsbl.cpp111
-rw-r--r--src/usermanager.cpp20
4 files changed, 92 insertions, 49 deletions
diff --git a/include/modules.h b/include/modules.h
index 6e8e685aa..10fc6ce80 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -97,7 +97,7 @@ struct ModResult {
/** If you change the module API in any way, increment this value.
* This MUST be a pure integer, with no parenthesis
*/
-#define API_VERSION 139
+#define API_VERSION 140
/**
* This #define allows us to call a method in all
@@ -316,7 +316,7 @@ enum Implementation
I_OnSendSnotice, I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper, I_OnInfo, I_OnWhois,
I_OnUserPreInvite, I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreNick,
I_OnUserMessage, I_OnUserNotice, I_OnMode, I_OnGetServerDescription, I_OnSyncUser,
- I_OnSyncChannel, I_OnDecodeMetaData, I_OnWallops, I_OnAcceptConnection,
+ I_OnSyncChannel, I_OnDecodeMetaData, I_OnWallops, I_OnAcceptConnection, I_OnUserInit,
I_OnChangeHost, I_OnChangeName, I_OnAddLine, I_OnDelLine, I_OnExpireLine,
I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule,
I_OnUnloadModule, I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnCheckInvite,
@@ -962,6 +962,11 @@ class CoreExport Module : public classbase, public usecountbase
*/
virtual void OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, LocalUser *user, CmdResult result, const std::string &original_line);
+ /** Called when a user is first connecting, prior to starting DNS lookups, checking initial
+ * connect class, or accepting any commands.
+ */
+ virtual void OnUserInit(LocalUser* user);
+
/** Called to check if a user who is connecting can now be allowed to register
* If any modules return false for this function, the user is held in the waiting
* state until all modules return true. For example a module which implements ident
diff --git a/src/modules.cpp b/src/modules.cpp
index bfe0deecb..6586166c8 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -101,6 +101,7 @@ void Module::OnUnloadModule(Module*) { }
void Module::OnBackgroundTimer(time_t) { }
ModResult Module::OnPreCommand(std::string&, std::vector<std::string>&, LocalUser*, bool, const std::string&) { return MOD_RES_PASSTHRU; }
void Module::OnPostCommand(const std::string&, const std::vector<std::string>&, LocalUser*, CmdResult, const std::string&) { }
+void Module::OnUserInit(LocalUser*) { }
ModResult Module::OnCheckReady(LocalUser*) { return MOD_RES_PASSTHRU; }
ModResult Module::OnUserRegister(LocalUser*) { return MOD_RES_PASSTHRU; }
ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { return MOD_RES_PASSTHRU; }
diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp
index 818450b79..eb3ff976d 100644
--- a/src/modules/m_dnsbl.cpp
+++ b/src/modules/m_dnsbl.cpp
@@ -46,24 +46,27 @@ class DNSBLConfEntry
class DNSBLResolver : public Resolver
{
std::string theiruid;
+ LocalStringExt& nameExt;
+ LocalIntExt& countExt;
DNSBLConfEntry *ConfEntry;
public:
- DNSBLResolver(Module *me, const std::string &hostname, LocalUser* u, DNSBLConfEntry *conf, bool &cached)
- : Resolver(hostname, DNS_QUERY_A, cached, me)
+ DNSBLResolver(Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, DNSBLConfEntry *conf, bool &cached)
+ : Resolver(hostname, DNS_QUERY_A, cached, me), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf)
{
- theiruid = u->uuid;
- ConfEntry = conf;
}
/* Note: This may be called multiple times for multiple A record results */
virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
{
/* Check the user still exists */
- User* them = ServerInstance->FindUUID(theiruid);
+ LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
if (them)
{
+ int i = countExt.get(them);
+ if (i)
+ countExt.set(them, i - 1);
// Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
if(result.length())
{
@@ -120,6 +123,7 @@ class DNSBLResolver : public Resolver
them->ChangeDisplayedHost(ConfEntry->host.c_str());
}
+ nameExt.set(them, ConfEntry->name);
break;
}
case DNSBLConfEntry::I_KLINE:
@@ -183,6 +187,13 @@ class DNSBLResolver : public Resolver
virtual void OnError(ResolverError e, const std::string &errormessage)
{
+ LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
+ if (them)
+ {
+ int i = countExt.get(them);
+ if (i)
+ countExt.set(them, i - 1);
+ }
}
virtual ~DNSBLResolver()
@@ -192,8 +203,9 @@ class DNSBLResolver : public Resolver
class ModuleDNSBL : public Module
{
- private:
std::vector<DNSBLConfEntry *> DNSBLConfEntries;
+ LocalStringExt nameExt;
+ LocalIntExt countExt;
/*
* Convert a string to EnumBanaction
@@ -214,10 +226,15 @@ class ModuleDNSBL : public Module
return DNSBLConfEntry::I_UNKNOWN;
}
public:
- ModuleDNSBL() {
+ ModuleDNSBL() : nameExt("dnsbl_match", this), countExt("dnsbl_pending", this) { }
+
+ void init()
+ {
ReadConf();
- Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnStats };
- ServerInstance->Modules->Attach(eventlist, this, 3);
+ ServerInstance->Modules->AddService(nameExt);
+ ServerInstance->Modules->AddService(countExt);
+ Implementation eventlist[] = { I_OnRehash, I_OnUserInit, I_OnStats, I_OnSetConnectClass, I_OnCheckReady };
+ ServerInstance->Modules->Attach(eventlist, this, 5);
}
virtual ~ModuleDNSBL()
@@ -225,12 +242,11 @@ class ModuleDNSBL : public Module
ClearEntries();
}
- virtual Version GetVersion()
+ Version GetVersion()
{
return Version("Provides handling of DNS blacklists", VF_VENDOR);
}
-
/** Clear entries and free the mem it was using
*/
void ClearEntries()
@@ -242,67 +258,68 @@ class ModuleDNSBL : public Module
/** Fill our conf vector with data
*/
- virtual void ReadConf()
+ void ReadConf()
{
- ConfigReader MyConf;
ClearEntries();
- for (int i=0; i< MyConf.Enumerate("dnsbl"); i++)
+ ConfigTagList dnsbls = ServerInstance->Config->ConfTags("dnsbl");
+ for(ConfigIter i = dnsbls.first; i != dnsbls.second; ++i)
{
+ ConfigTag* tag = i->second;
DNSBLConfEntry *e = new DNSBLConfEntry();
- e->name = MyConf.ReadValue("dnsbl", "name", i);
- e->ident = MyConf.ReadValue("dnsbl", "ident", i);
- e->host = MyConf.ReadValue("dnsbl", "host", i);
- e->reason = MyConf.ReadValue("dnsbl", "reason", i);
- e->domain = MyConf.ReadValue("dnsbl", "domain", i);
+ e->name = tag->getString("name");
+ e->ident = tag->getString("ident");
+ e->host = tag->getString("host");
+ e->reason = tag->getString("reason");
+ e->domain = tag->getString("domain");
- if (MyConf.ReadValue("dnsbl", "type", i) == "bitmask")
+ if (tag->getString("type") == "bitmask")
{
e->type = DNSBLConfEntry::A_BITMASK;
- e->bitmask = MyConf.ReadInteger("dnsbl", "bitmask", i, false);
+ e->bitmask = tag->getInt("bitmask");
}
else
{
memset(e->records, 0, sizeof(e->records));
e->type = DNSBLConfEntry::A_RECORD;
- irc::portparser portrange(MyConf.ReadValue("dnsbl", "records", i), false);
+ irc::portparser portrange(tag->getString("records"), false);
long item = -1;
while ((item = portrange.GetToken()))
e->records[item] = 1;
}
- e->banaction = str2banaction(MyConf.ReadValue("dnsbl", "action", i));
- e->duration = ServerInstance->Duration(MyConf.ReadValue("dnsbl", "duration", "60", i));
+ e->banaction = str2banaction(tag->getString("action"));
+ e->duration = ServerInstance->Duration(tag->getString("duration", "60"));
/* Use portparser for record replies */
/* yeah, logic here is a little messy */
if ((e->bitmask <= 0) && (DNSBLConfEntry::A_BITMASK == e->type))
{
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(#%d): invalid bitmask",i);
+ ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): invalid bitmask",tag->getTagLocation().c_str());
}
else if (e->name.empty())
{
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(#%d): Invalid name",i);
+ ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid name",tag->getTagLocation().c_str());
}
else if (e->domain.empty())
{
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(#%d): Invalid domain",i);
+ ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid domain",tag->getTagLocation().c_str());
}
else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)
{
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(#%d): Invalid banaction", i);
+ ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid banaction",tag->getTagLocation().c_str());
}
else if (e->duration <= 0)
{
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(#%d): Invalid duration", i);
+ ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid duration",tag->getTagLocation().c_str());
}
else
{
if (e->reason.empty())
{
- ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(#%d): empty reason, using defaults",i);
+ ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): empty reason, using defaults",tag->getTagLocation().c_str());
e->reason = "Your IP has been blacklisted.";
}
@@ -316,12 +333,12 @@ class ModuleDNSBL : public Module
}
}
- virtual void OnRehash(User* user)
+ void OnRehash(User* user)
{
ReadConf();
}
- virtual ModResult OnUserRegister(LocalUser* user)
+ void OnUserInit(LocalUser* user)
{
/* following code taken from bopm, reverses an IP address. */
struct in_addr in;
@@ -333,7 +350,7 @@ class ModuleDNSBL : public Module
success = inet_aton(user->GetIPString(), &in);
if (!success)
- return MOD_RES_PASSTHRU;
+ return;
d = (unsigned char) (in.s_addr >> 24) & 0xFF;
c = (unsigned char) (in.s_addr >> 16) & 0xFF;
@@ -344,22 +361,40 @@ class ModuleDNSBL : public Module
reversedip = std::string(reversedipbuf);
// For each DNSBL, we will run through this lookup
- for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
+ unsigned int i = 0;
+ while (i < DNSBLConfEntries.size())
{
// Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)
- std::string hostname = reversedip + "." + (*i)->domain;
+ std::string hostname = reversedip + "." + DNSBLConfEntries[i]->domain;
/* now we'd need to fire off lookups for `hostname'. */
bool cached;
- DNSBLResolver *r = new DNSBLResolver(this, hostname, user, *i, cached);
+ DNSBLResolver *r = new DNSBLResolver(this, nameExt, countExt, hostname, user, DNSBLConfEntries[i], cached);
ServerInstance->AddResolver(r, cached);
}
+ countExt.set(user, i);
+ }
- /* don't do anything with this hot potato */
+ ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
+ {
+ std::string dnsbl;
+ if (!myclass->config->readString("dnsbl", dnsbl))
+ return MOD_RES_PASSTHRU;
+ std::string* match = nameExt.get(user);
+ std::string myname = match ? *match : "";
+ if (dnsbl == myname)
+ return MOD_RES_PASSTHRU;
+ return MOD_RES_DENY;
+ }
+
+ ModResult OnCheckReady(LocalUser *user)
+ {
+ if (countExt.get(user))
+ return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
- virtual ModResult OnStats(char symbol, User* user, string_list &results)
+ ModResult OnStats(char symbol, User* user, string_list &results)
{
if (symbol != 'd')
return MOD_RES_PASSTHRU;
diff --git a/src/usermanager.cpp b/src/usermanager.cpp
index 9f5f8c937..588af9510 100644
--- a/src/usermanager.cpp
+++ b/src/usermanager.cpp
@@ -70,6 +70,17 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
ServerInstance->Users->AddLocalClone(New);
ServerInstance->Users->AddGlobalClone(New);
+ this->local_users.push_back(New);
+
+ if ((this->local_users.size() > ServerInstance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)ServerInstance->SE->GetMaxFds()))
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit);
+ this->QuitUser(New,"No more connections allowed");
+ return;
+ }
+
+ FOREACH_MOD(I_OnUserInit,OnUserInit(New));
+
/*
* First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
* See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
@@ -82,15 +93,6 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
*/
New->CheckClass();
- this->local_users.push_back(New);
-
- if ((this->local_users.size() > ServerInstance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)ServerInstance->SE->GetMaxFds()))
- {
- ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit);
- this->QuitUser(New,"No more connections allowed");
- return;
- }
-
/*
* even with bancache, we still have to keep User::exempt current.
* besides that, if we get a positive bancache hit, we still won't fuck