1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
17 #include "inspircd_config.h"
18 #include "configreader.h"
26 /* $ModDesc: Provides masking of user hostnames */
27 /* $ModDep: m_md5.h */
29 /* Used to vary the output a little more depending on the cloak keys */
30 static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};
32 /** Handles user mode +x
34 class CloakUser : public ModeHandler
46 CloakUser(InspIRCd* Instance, Module* Source, Module* MD5) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), MD5Provider(MD5)
50 ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
52 /* Only opers can change other users modes */
53 if ((source != dest) && (!*source->oper))
54 return MODEACTION_DENY;
56 /* For remote clients, we dont take any action, we just allow it.
57 * The local server where they are will set their cloak instead.
60 return MODEACTION_ALLOW;
64 if(!dest->IsModeSet('x'))
66 /* The mode is being turned on - so attempt to
67 * allocate the user a cloaked host using a non-reversible
68 * algorithm (its simple, but its non-reversible so the
69 * simplicity doesnt really matter). This algorithm
70 * will not work if the user has only one level of domain
71 * naming in their hostname (e.g. if they are on a lan or
72 * are connecting via localhost) -- this doesnt matter much.
75 if (strchr(dest->host,'.') || strchr(dest->host,':'))
77 /* InspIRCd users have two hostnames; A displayed
78 * hostname which can be modified by modules (e.g.
79 * to create vhosts, implement chghost, etc) and a
80 * 'real' hostname which you shouldnt write to.
83 unsigned int iv[] = { key1, key2, key3, key4 };
84 char* n = strstr(dest->host,".");
86 n = strstr(dest->host,":");
93 /** Reset the MD5 module, and send it our IV and hex table */
94 MD5ResetRequest(Sender, MD5Provider).Send();
95 MD5KeyRequest(Sender, MD5Provider, iv).Send();
96 MD5HexRequest(Sender, MD5Provider, xtab[0]);
98 /* Generate a cloak using specialized MD5 */
99 std::string hostcloak = prefix + "-" + MD5SumRequest(Sender, MD5Provider, dest->host).Send() + a;
101 /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
102 * according to the DNS RFC) then tough titty, they get cloaked as an IP.
103 * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie
107 if ((insp_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
109 // if they have a hostname, make something appropriate
114 b = ((b.find(':') == std::string::npos) ? Cloak4(dest->host) : Cloak6(dest->host));
116 dest->ChangeDisplayedHost(b.c_str());
119 dest->SetMode('x',true);
120 return MODEACTION_ALLOW;
125 if (dest->IsModeSet('x'))
127 /* User is removing the mode, so just restore their real host
128 * and make it match the displayed one.
130 dest->ChangeDisplayedHost(dest->host);
131 dest->SetMode('x',false);
132 return MODEACTION_ALLOW;
136 return MODEACTION_DENY;
139 std::string Cloak4(const char* ip)
141 unsigned int iv[] = { key1, key2, key3, key4 };
142 irc::sepstream seps(ip, '.');
143 std::string ra1, ra2, ra3, ra4;
144 std::string octet1 = seps.GetToken();
145 std::string octet2 = seps.GetToken();
146 std::string octet3 = seps.GetToken();
147 std::string octet4 = seps.GetToken();
148 int i1 = atoi(octet1.c_str());
149 int i2 = atoi(octet2.c_str());
150 int i3 = atoi(octet3.c_str());
151 int i4 = atoi(octet4.c_str());
153 octet4 = octet1 + "." + octet2 + "." + octet3 + "." + octet4;
154 octet3 = octet1 + "." + octet2 + "." + octet3;
155 octet2 = octet1 + "." + octet2;
157 /* Reset the MD5 module and send it our IV */
158 MD5ResetRequest(Sender, MD5Provider).Send();
159 MD5KeyRequest(Sender, MD5Provider, iv).Send();
161 /* Send the MD5 module a different hex table for each octet group's MD5 sum */
162 MD5HexRequest(Sender, MD5Provider, xtab[(key1+i1) % 4]).Send();
163 ra1 = std::string(MD5SumRequest(Sender, MD5Provider, octet1).Send()).substr(0,6);
165 MD5HexRequest(Sender, MD5Provider, xtab[(key2+i2) % 4]).Send();
166 ra2 = std::string(MD5SumRequest(Sender, MD5Provider, octet2).Send()).substr(0,6);
168 MD5HexRequest(Sender, MD5Provider, xtab[(key3+i3) % 4]).Send();
169 ra3 = std::string(MD5SumRequest(Sender, MD5Provider, octet3).Send()).substr(0,6);
171 MD5HexRequest(Sender, MD5Provider, xtab[(key4+i4) % 4]).Send();
172 ra4 = std::string(MD5SumRequest(Sender, MD5Provider, octet4).Send()).substr(0,6);
174 /* Stick them all together */
175 return std::string().append(ra1).append(".").append(ra2).append(".").append(ra3).append(".").append(ra4);
178 std::string Cloak6(const char* ip)
180 unsigned int iv[] = { key1, key2, key3, key4 };
181 std::vector<std::string> hashies;
182 std::string item = "";
185 /* Reset the MD5 module and send it our IV */
186 MD5ResetRequest(Sender, MD5Provider).Send();
187 MD5KeyRequest(Sender, MD5Provider, iv).Send();
189 for (const char* input = ip; *input; input++)
192 if (item.length() > 5)
194 /* Send the MD5 module a different hex table for each octet group's MD5 sum */
195 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
196 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
203 /* Send the MD5 module a different hex table for each octet group's MD5 sum */
204 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
205 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
208 /* Stick them all together */
209 return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
214 ConfigReader Conf(ServerInstance);
215 key1 = key2 = key3 = key4 = 0;
216 key1 = Conf.ReadInteger("cloak","key1",0,true);
217 key2 = Conf.ReadInteger("cloak","key2",0,true);
218 key3 = Conf.ReadInteger("cloak","key3",0,true);
219 key4 = Conf.ReadInteger("cloak","key4",0,true);
220 prefix = Conf.ReadValue("cloak","prefix",0);
223 prefix = ServerInstance->Config->Network;
225 if (!key1 && !key2 && !key3 && !key4)
227 ModuleException ex("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
234 class ModuleCloaking : public Module
242 ModuleCloaking(InspIRCd* Me)
245 /* Attempt to locate the MD5 service provider, bail if we can't find it */
246 MD5Module = ServerInstance->FindModule("m_md5.so");
248 throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
250 /* Create new mode handler object */
251 cu = new CloakUser(ServerInstance, this, MD5Module);
253 /* Register it with the core */
254 ServerInstance->AddMode(cu, 'x');
259 virtual ~ModuleCloaking()
261 ServerInstance->Modes->DelMode(cu);
265 virtual Version GetVersion()
267 // returns the version number of the module to be
268 // listed in /MODULES
269 return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);
272 virtual void OnRehash(const std::string ¶meter)
277 void Implements(char* List)
279 List[I_OnRehash] = 1;
283 // stuff down here is the module-factory stuff. For basic modules you can ignore this.
285 class ModuleCloakingFactory : public ModuleFactory
288 ModuleCloakingFactory()
292 ~ModuleCloakingFactory()
296 virtual Module * CreateModule(InspIRCd* Me)
298 return new ModuleCloaking(Me);
304 extern "C" void * init_module( void )
306 return new ModuleCloakingFactory;