00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "m_hash.h"
00016
00017
00018
00019
00022 class CloakUser : public ModeHandler
00023 {
00024 public:
00025 std::string prefix;
00026 unsigned int key1;
00027 unsigned int key2;
00028 unsigned int key3;
00029 unsigned int key4;
00030 bool ipalways;
00031 Module* Sender;
00032 Module* HashProvider;
00033 const char *xtab[4];
00034
00044 std::string LastTwoDomainParts(const std::string &host)
00045 {
00046 int dots = 0;
00047 std::string::size_type splitdot = host.length();
00048
00049 for (std::string::size_type x = host.length() - 1; x; --x)
00050 {
00051 if (host[x] == '.')
00052 {
00053 splitdot = x;
00054 dots++;
00055 }
00056 if (dots >= 3)
00057 break;
00058 }
00059
00060 if (splitdot == host.length())
00061 return host;
00062 else
00063 return host.substr(splitdot);
00064 }
00065
00066 CloakUser(InspIRCd* Instance, Module* source, Module* Hash) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(source), HashProvider(Hash)
00067 {
00068 }
00069
00070 ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool)
00071 {
00072
00073
00074
00075
00076 if (!IS_LOCAL(dest))
00077 {
00078 dest->SetMode('x',adding);
00079 return MODEACTION_ALLOW;
00080 }
00081
00082
00083 dest->IncreasePenalty(5);
00084
00085 if (adding)
00086 {
00087 if(!dest->IsModeSet('x'))
00088 {
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 std::string* cloak;
00099
00100 if (!dest->GetExt("cloaked_host", cloak))
00101 {
00102
00103 Sender->OnUserConnect(dest);
00104 }
00105 if (dest->GetExt("cloaked_host", cloak))
00106 {
00107 dest->ChangeDisplayedHost(cloak->c_str());
00108 dest->SetMode('x',true);
00109 return MODEACTION_ALLOW;
00110 }
00111 }
00112 }
00113 else
00114 {
00115 if (dest->IsModeSet('x'))
00116 {
00117
00118
00119
00120 dest->ChangeDisplayedHost(dest->host.c_str());
00121 dest->SetMode('x',false);
00122 return MODEACTION_ALLOW;
00123 }
00124 }
00125
00126 return MODEACTION_DENY;
00127 }
00128
00129 std::string Cloak4(const char* ip)
00130 {
00131 unsigned int iv[] = { key1, key2, key3, key4 };
00132 irc::sepstream seps(ip, '.');
00133 std::string ra[4];;
00134 std::string octet[4];
00135 int i[4];
00136
00137 for (int j = 0; j < 4; j++)
00138 {
00139 seps.GetToken(octet[j]);
00140 i[j] = atoi(octet[j].c_str());
00141 }
00142
00143 octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3];
00144 octet[2] = octet[0] + "." + octet[1] + "." + octet[2];
00145 octet[1] = octet[0] + "." + octet[1];
00146
00147
00148 HashResetRequest(Sender, HashProvider).Send();
00149 HashKeyRequest(Sender, HashProvider, iv).Send();
00150
00151
00152 for (int k = 0; k < 4; k++)
00153 {
00154 HashHexRequest(Sender, HashProvider, xtab[(iv[k]+i[k]) % 4]).Send();
00155 ra[k] = std::string(HashSumRequest(Sender, HashProvider, octet[k]).Send()).substr(0,6);
00156 }
00157
00158 return std::string().append(ra[0]).append(".").append(ra[1]).append(".").append(ra[2]).append(".").append(ra[3]);
00159 }
00160
00161 std::string Cloak6(const char* ip)
00162 {
00163 unsigned int iv[] = { key1, key2, key3, key4 };
00164 std::vector<std::string> hashies;
00165 std::string item;
00166 int rounds = 0;
00167
00168
00169 HashResetRequest(Sender, HashProvider).Send();
00170 HashKeyRequest(Sender, HashProvider, iv).Send();
00171
00172 for (const char* input = ip; *input; input++)
00173 {
00174 item += *input;
00175 if (item.length() > 7)
00176 {
00177
00178 HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();
00179 hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));
00180 item.clear();
00181 }
00182 rounds++;
00183 }
00184 if (!item.empty())
00185 {
00186
00187 HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();
00188 hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));
00189 item.clear();
00190 }
00191
00192 return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
00193 }
00194
00195 void DoRehash()
00196 {
00197 ConfigReader Conf(ServerInstance);
00198 bool lowercase;
00199
00200
00201
00202
00203
00204
00205 key1 = key2 = key3 = key4 = 0;
00206 key1 = (unsigned int) Conf.ReadInteger("cloak","key1",0,false);
00207 key2 = (unsigned int) Conf.ReadInteger("cloak","key2",0,false);
00208 key3 = (unsigned int) Conf.ReadInteger("cloak","key3",0,false);
00209 key4 = (unsigned int) Conf.ReadInteger("cloak","key4",0,false);
00210 prefix = Conf.ReadValue("cloak","prefix",0);
00211 ipalways = Conf.ReadFlag("cloak", "ipalways", 0);
00212 lowercase = Conf.ReadFlag("cloak", "lowercase", 0);
00213
00214 if (!lowercase)
00215 {
00216 xtab[0] = "F92E45D871BCA630";
00217 xtab[1] = "A1B9D80C72E653F4";
00218 xtab[2] = "1ABC078934DEF562";
00219 xtab[3] = "ABCDEF5678901234";
00220 }
00221 else
00222 {
00223 xtab[0] = "f92e45d871bca630";
00224 xtab[1] = "a1b9d80c72e653f4";
00225 xtab[2] = "1abc078934def562";
00226 xtab[3] = "abcdef5678901234";
00227 }
00228
00229 if (prefix.empty())
00230 prefix = ServerInstance->Config->Network;
00231
00232 if (!key1 || !key2 || !key3 || !key4)
00233 {
00234 std::string detail;
00235 if (!key1)
00236 detail = "<cloak:key1> is not valid, it may be set to a too high/low value, or it may not exist.";
00237 else if (!key2)
00238 detail = "<cloak:key2> is not valid, it may be set to a too high/low value, or it may not exist.";
00239 else if (!key3)
00240 detail = "<cloak:key3> is not valid, it may be set to a too high/low value, or it may not exist.";
00241 else if (!key4)
00242 detail = "<cloak:key4> is not valid, it may be set to a too high/low value, or it may not exist.";
00243
00244 throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED! - " + detail);
00245 }
00246 }
00247 };
00248
00249
00250 class ModuleCloaking : public Module
00251 {
00252 private:
00253
00254 CloakUser* cu;
00255 Module* HashModule;
00256
00257 public:
00258 ModuleCloaking(InspIRCd* Me)
00259 : Module(Me)
00260 {
00261
00262 HashModule = ServerInstance->Modules->Find("m_md5.so");
00263 if (!HashModule)
00264 throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
00265
00266 cu = new CloakUser(ServerInstance, this, HashModule);
00267
00268 try
00269 {
00270 OnRehash(NULL,"");
00271 }
00272 catch (ModuleException &e)
00273 {
00274 delete cu;
00275 throw e;
00276 }
00277
00278
00279 if (!ServerInstance->Modes->AddMode(cu))
00280 {
00281 delete cu;
00282 throw ModuleException("Could not add new modes!");
00283 }
00284
00285 ServerInstance->Modules->UseInterface("HashRequest");
00286
00287 Implementation eventlist[] = { I_OnRehash, I_OnUserDisconnect, I_OnCleanup, I_OnCheckBan, I_OnUserConnect, I_OnSyncUserMetaData, I_OnCleanup };
00288 ServerInstance->Modules->Attach(eventlist, this, 6);
00289
00290 CloakExistingUsers();
00291 }
00292
00293 void OnSyncUserMetaData(User* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
00294 {
00295 if ((displayable) && (extname == "cloaked_host"))
00296 {
00297 std::string* cloak;
00298 if (user->GetExt("cloaked_host", cloak))
00299 proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *cloak);
00300 }
00301 }
00302
00303 void CloakExistingUsers()
00304 {
00305 std::string* cloak;
00306 for (std::vector<User*>::iterator u = ServerInstance->Users->local_users.begin(); u != ServerInstance->Users->local_users.end(); u++)
00307 {
00308 if (!(*u)->GetExt("cloaked_host", cloak))
00309 {
00310 OnUserConnect(*u);
00311 }
00312 }
00313 }
00314
00315 virtual int OnCheckBan(User* user, Channel* chan)
00316 {
00317 char mask[MAXBUF];
00318 std::string* tofree;
00319
00320 if (user->GetExt("cloaked_host", tofree) && *tofree != user->dhost)
00321 {
00322 snprintf(mask, MAXBUF, "%s!%s@%s", user->nick.c_str(), user->ident.c_str(), tofree->c_str());
00323 for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
00324 {
00325 if (InspIRCd::Match(mask,i->data))
00326 return -1;
00327 }
00328 }
00329 return 0;
00330 }
00331
00332 void Prioritize()
00333 {
00334
00335 ServerInstance->Modules->SetPriority(this, I_OnCheckBan, PRIO_LAST);
00336
00337
00338 Module *um = ServerInstance->Modules->Find("m_conn_umodes.so");
00339 ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIO_AFTER, &um);
00340 }
00341
00342 virtual void OnUserDisconnect(User* user)
00343 {
00344 std::string* tofree;
00345 if (user->GetExt("cloaked_host", tofree))
00346 {
00347 delete tofree;
00348 user->Shrink("cloaked_host");
00349 }
00350 }
00351
00352 virtual void OnCleanup(int target_type, void* item)
00353 {
00354 if (target_type == TYPE_USER)
00355 OnUserDisconnect((User*)item);
00356 }
00357
00358 virtual ~ModuleCloaking()
00359 {
00360 ServerInstance->Modes->DelMode(cu);
00361 delete cu;
00362 ServerInstance->Modules->DoneWithInterface("HashRequest");
00363 }
00364
00365 virtual Version GetVersion()
00366 {
00367
00368
00369 return Version("$Id: m_cloaking.cpp 10781 2008-11-01 20:20:12Z w00t $", VF_COMMON|VF_VENDOR,API_VERSION);
00370 }
00371
00372 virtual void OnRehash(User* user, const std::string ¶meter)
00373 {
00374 cu->DoRehash();
00375 }
00376
00377 virtual void OnUserConnect(User* dest)
00378 {
00379 std::string* tofree;
00380 if (dest->GetExt("cloaked_host", tofree))
00381 return;
00382
00383 if (dest->host.find('.') != std::string::npos || dest->host.find(':') != std::string::npos)
00384 {
00385 unsigned int iv[] = { cu->key1, cu->key2, cu->key3, cu->key4 };
00386 std::string a = cu->LastTwoDomainParts(dest->host);
00387 std::string b;
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 if (!cu->ipalways)
00399 {
00401 HashResetRequest(this, cu->HashProvider).Send();
00402 HashKeyRequest(this, cu->HashProvider, iv).Send();
00403 HashHexRequest(this, cu->HashProvider, cu->xtab[(dest->host[0]) % 4]);
00404
00405
00406 std::string hostcloak = cu->prefix + "-" + std::string(HashSumRequest(this, cu->HashProvider, dest->host.c_str()).Send()).substr(0,8) + a;
00407
00408
00409
00410
00411
00412
00413 #ifdef IPV6
00414 in6_addr testaddr;
00415 in_addr testaddr2;
00416 if ((dest->GetProtocolFamily() == AF_INET6) && (inet_pton(AF_INET6,dest->host.c_str(),&testaddr) < 1) && (hostcloak.length() <= 64))
00417
00418 b = hostcloak;
00419 else if ((dest->GetProtocolFamily() == AF_INET) && (inet_aton(dest->host.c_str(),&testaddr2) < 1) && (hostcloak.length() <= 64))
00420
00421 b = hostcloak;
00422 else
00423
00424 b = ((!strchr(dest->host.c_str(),':')) ? cu->Cloak4(dest->host.c_str()) : cu->Cloak6(dest->host.c_str()));
00425 #else
00426 in_addr testaddr;
00427 if ((inet_aton(dest->host.c_str(),&testaddr) < 1) && (hostcloak.length() <= 64))
00428
00429 b = hostcloak;
00430 else
00431
00432 b = cu->Cloak4(dest->host.c_str());
00433 #endif
00434 }
00435 else
00436 {
00437 #ifdef IPV6
00438 if (dest->GetProtocolFamily() == AF_INET6)
00439 b = cu->Cloak6(dest->GetIPString());
00440 #endif
00441 if (dest->GetProtocolFamily() == AF_INET)
00442 b = cu->Cloak4(dest->GetIPString());
00443 }
00444
00445 dest->Extend("cloaked_host", new std::string(b));
00446 }
00447 }
00448
00449 };
00450
00451 MODULE_INIT(ModuleCloaking)