1 /* 2 * InspIRCd -- Internet Relay Chat Daemon 3 * 4 * Copyright (C) 2019 Matt Schatz <genius3000@g3k.solutions> 5 * Copyright (C) 2014 Googolplexed <googol@googolplexed.net> 6 * Copyright (C) 2013, 2017-2021 Sadie Powell <sadie@witchery.services> 7 * Copyright (C) 2012-2014 Attila Molnar <attilamolnar@hush.com> 8 * Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be> 9 * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> 10 * Copyright (C) 2008, 2010 Craig Edwards <brain@inspircd.org> 11 * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> 12 * 13 * This file is part of InspIRCd. InspIRCd is free software: you can 14 * redistribute it and/or modify it under the terms of the GNU General Public 15 * License as published by the Free Software Foundation, version 2. 16 * 17 * This program is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 20 * details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 27 #include "inspircd.h" 28 #include "xline.h" 29 #include "modules/server.h" 30 #include "modules/webirc.h" 31 32 class ModuleConnectBan CXX11_FINAL 33 : public Module 34 , public ServerProtocol::LinkEventListener 35 , public WebIRC::EventListener 36 { 37 private: 38 typedef std::map<irc::sockets::cidr_mask, unsigned int> ConnectMap; 39 40 ConnectMap connects; 41 unsigned int threshold; 42 unsigned int banduration; 43 unsigned int ipv4_cidr; 44 unsigned int ipv6_cidr; 45 unsigned long bootwait; 46 unsigned long splitwait; 47 time_t ignoreuntil; 48 std::string banmessage; 49 GetRange(LocalUser * user)50 unsigned char GetRange(LocalUser* user) 51 { 52 int family = user->client_sa.family(); 53 switch (family) 54 { 55 case AF_INET: 56 return ipv4_cidr; 57 58 case AF_INET6: 59 return ipv6_cidr; 60 61 case AF_UNIX: 62 // Ranges for UNIX sockets are ignored entirely. 63 return 0; 64 } 65 66 // If we have reached this point then we have encountered a bug. 67 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: ModuleConnectBan::GetRange(): socket type %d is unknown!", family); 68 return 0; 69 } 70 IsExempt(LocalUser * user)71 static bool IsExempt(LocalUser* user) 72 { 73 // E-lined and already banned users shouldn't be hit. 74 if (user->exempt || user->quitting) 75 return true; 76 77 // Users in an exempt class shouldn't be hit. 78 return user->GetClass() && !user->GetClass()->config->getBool("useconnectban", true); 79 } 80 81 public: 82 // Stop GCC warnings about the deprecated OnServerSplit event. 83 using ServerProtocol::LinkEventListener::OnServerSplit; 84 ModuleConnectBan()85 ModuleConnectBan() 86 : ServerProtocol::LinkEventListener(this) 87 , WebIRC::EventListener(this) 88 , ignoreuntil(0) 89 { 90 } 91 Prioritize()92 void Prioritize() CXX11_OVERRIDE 93 { 94 Module* corexline = ServerInstance->Modules->Find("core_xline"); 95 ServerInstance->Modules->SetPriority(this, I_OnSetUserIP, PRIORITY_AFTER, corexline); 96 } 97 GetVersion()98 Version GetVersion() CXX11_OVERRIDE 99 { 100 return Version("Z-lines IP addresses which make excessive connections to the server.", VF_VENDOR); 101 } 102 ReadConfig(ConfigStatus & status)103 void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE 104 { 105 ConfigTag* tag = ServerInstance->Config->ConfValue("connectban"); 106 107 ipv4_cidr = tag->getUInt("ipv4cidr", 32, 1, 32); 108 ipv6_cidr = tag->getUInt("ipv6cidr", 128, 1, 128); 109 threshold = tag->getUInt("threshold", 10, 1); 110 bootwait = tag->getDuration("bootwait", 60*2); 111 splitwait = tag->getDuration("splitwait", 60*2); 112 banduration = tag->getDuration("duration", 10*60, 1); 113 banmessage = tag->getString("banmessage", "Your IP range has been attempting to connect too many times in too short a duration. Wait a while, and you will be able to connect."); 114 115 if (status.initial) 116 ignoreuntil = ServerInstance->Time() + bootwait; 117 } 118 OnWebIRCAuth(LocalUser * user,const WebIRC::FlagMap * flags)119 void OnWebIRCAuth(LocalUser* user, const WebIRC::FlagMap* flags) CXX11_OVERRIDE 120 { 121 if (IsExempt(user)) 122 return; 123 124 // HACK: Lower the connection attempts for the gateway IP address. The user 125 // will be rechecked for connect spamming shortly after when their IP address 126 // is changed and OnSetUserIP is called. 127 irc::sockets::cidr_mask mask(user->client_sa, GetRange(user)); 128 ConnectMap::iterator iter = connects.find(mask); 129 if (iter != connects.end() && iter->second) 130 iter->second--; 131 } 132 OnServerSplit(const Server * server,bool error)133 void OnServerSplit(const Server* server, bool error) CXX11_OVERRIDE 134 { 135 if (splitwait) 136 ignoreuntil = std::max<time_t>(ignoreuntil, ServerInstance->Time() + splitwait); 137 } 138 OnSetUserIP(LocalUser * u)139 void OnSetUserIP(LocalUser* u) CXX11_OVERRIDE 140 { 141 if (IsExempt(u) || ignoreuntil > ServerInstance->Time()) 142 return; 143 144 irc::sockets::cidr_mask mask(u->client_sa, GetRange(u)); 145 ConnectMap::iterator i = connects.find(mask); 146 147 if (i != connects.end()) 148 { 149 i->second++; 150 151 if (i->second >= threshold) 152 { 153 // Create Z-line for set duration. 154 ZLine* zl = new ZLine(ServerInstance->Time(), banduration, ServerInstance->Config->ServerName, banmessage, mask.str()); 155 if (!ServerInstance->XLines->AddLine(zl, NULL)) 156 { 157 delete zl; 158 return; 159 } 160 ServerInstance->XLines->ApplyLines(); 161 std::string maskstr = mask.str(); 162 ServerInstance->SNO->WriteGlobalSno('x', "Z-line added by module m_connectban on %s to expire in %s (on %s): Connect flooding", 163 maskstr.c_str(), InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str()); 164 ServerInstance->SNO->WriteGlobalSno('a', "Connect flooding from IP range %s (%d)", maskstr.c_str(), threshold); 165 connects.erase(i); 166 } 167 } 168 else 169 { 170 connects[mask] = 1; 171 } 172 } 173 OnGarbageCollect()174 void OnGarbageCollect() CXX11_OVERRIDE 175 { 176 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Clearing map."); 177 connects.clear(); 178 } 179 }; 180 181 MODULE_INIT(ModuleConnectBan) 182