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 static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};
31 /** Handles user mode +x
33 class CloakUser : public ModeHandler
45 CloakUser(InspIRCd* Instance, Module* Source, Module* MD5) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), MD5Provider(MD5)
49 ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
51 /* Only opers can change other users modes */
52 if ((source != dest) && (!*source->oper))
53 return MODEACTION_DENY;
55 /* For remote clients, we dont take any action, we just allow it.
56 * The local server where they are will set their cloak instead.
59 return MODEACTION_ALLOW;
63 if(!dest->IsModeSet('x'))
65 /* The mode is being turned on - so attempt to
66 * allocate the user a cloaked host using a non-reversible
67 * algorithm (its simple, but its non-reversible so the
68 * simplicity doesnt really matter). This algorithm
69 * will not work if the user has only one level of domain
70 * naming in their hostname (e.g. if they are on a lan or
71 * are connecting via localhost) -- this doesnt matter much.
74 if (strchr(dest->host,'.') || strchr(dest->host,':'))
76 /* InspIRCd users have two hostnames; A displayed
77 * hostname which can be modified by modules (e.g.
78 * to create vhosts, implement chghost, etc) and a
79 * 'real' hostname which you shouldnt write to.
82 char* n = strstr(dest->host,".");
84 n = strstr(dest->host,":");
90 std::string hostcloak = prefix + "-" + MD5SumRequest(Sender, MD5Provider, dest->host).Send() + a;
92 /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
93 * according to the DNS RFC) then tough titty, they get cloaked as an IP.
94 * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie
98 if ((insp_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
100 // if they have a hostname, make something appropriate
105 b = ((b.find(':') == std::string::npos) ? Cloak4(dest->host) : Cloak6(dest->host));
107 ServerInstance->Log(DEBUG,"cloak: allocated "+b);
108 dest->ChangeDisplayedHost(b.c_str());
111 dest->SetMode('x',true);
112 return MODEACTION_ALLOW;
117 if (dest->IsModeSet('x'))
119 /* User is removing the mode, so just restore their real host
120 * and make it match the displayed one.
122 dest->ChangeDisplayedHost(dest->host);
123 dest->SetMode('x',false);
124 return MODEACTION_ALLOW;
128 return MODEACTION_DENY;
131 std::string Cloak4(const char* ip)
133 unsigned int iv[] = { key1, key2, key3, key4 };
134 irc::sepstream seps(ip, '.');
135 std::string ra1, ra2, ra3, ra4;
137 std::string octet1 = seps.GetToken();
138 std::string octet2 = seps.GetToken();
139 std::string octet3 = seps.GetToken();
140 std::string octet4 = seps.GetToken();
141 i1 = atoi(octet1.c_str());
142 i2 = atoi(octet2.c_str());
143 i3 = atoi(octet3.c_str());
144 i4 = atoi(octet4.c_str());
145 octet4 = octet1 + "." + octet2 + "." + octet3 + "." + octet4;
146 octet3 = octet1 + "." + octet2 + "." + octet3;
147 octet2 = octet1 + "." + octet2;
149 MD5ResetRequest(Sender, MD5Provider).Send();
150 MD5KeyRequest(Sender, MD5Provider, iv).Send();
152 MD5HexRequest(Sender, MD5Provider, xtab[(key1+i1) % 4]).Send();
153 ra1 = std::string(MD5SumRequest(Sender, MD5Provider, octet1).Send()).substr(0,6);
155 MD5HexRequest(Sender, MD5Provider, xtab[(key2+i2) % 4]).Send();
156 ra2 = std::string(MD5SumRequest(Sender, MD5Provider, octet2).Send()).substr(0,6);
158 MD5HexRequest(Sender, MD5Provider, xtab[(key3+i3) % 4]).Send();
159 ra3 = std::string(MD5SumRequest(Sender, MD5Provider, octet3).Send()).substr(0,6);
161 MD5HexRequest(Sender, MD5Provider, xtab[(key4+i4) % 4]).Send();
162 ra4 = std::string(MD5SumRequest(Sender, MD5Provider, octet4).Send()).substr(0,6);
164 /* This is safe as we know the length generated by our genhash is always 16 */
165 return std::string().append(ra1).append(".").append(ra2).append(".").append(ra3).append(".").append(ra4);
168 std::string Cloak6(const char* ip)
170 unsigned int iv[] = { key1, key2, key3, key4 };
171 std::vector<std::string> hashies;
172 std::string item = "";
175 MD5ResetRequest(Sender, MD5Provider).Send();
176 MD5KeyRequest(Sender, MD5Provider, iv).Send();
178 for (const char* input = ip; *input; input++)
181 if (item.length() > 5)
183 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
184 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
191 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
192 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
195 return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
198 /* XXX: Uncomment and call to use the test suite
201 printf("%s %s\n", "192.168.1.1", Cloak4("192.168.1.1").c_str());
202 printf("%s %s\n", "192.168.1.2", Cloak4("192.168.1.2").c_str());
203 printf("%s %s\n", "192.168.10.1", Cloak4("192.168.10.1").c_str());
204 printf("%s %s\n", "192.168.10.1", Cloak4("192.168.10.2").c_str());
205 printf("%s %s\n", "192.169.1.1", Cloak4("192.169.1.1").c_str());
206 printf("%s %s\n", "192.169.2.1", Cloak4("192.169.2.1").c_str());
207 printf("%s %s\n", "200.168.1.1", Cloak4("200.168.1.1").c_str());
208 printf("%s %s\n", "200.168.1.3", Cloak4("200.168.1.3").c_str());
209 printf("%s %s\n", "200.168.3.3", Cloak4("200.168.3.3").c_str());
210 printf("%s %s\n", "200.169.4.3", Cloak4("200.169.4.3").c_str());
212 printf("%s %s\n", "9a05:2f00:3f11::5f12::1", Cloak6("9a05:2f00:3f11::5f12::1").c_str());
213 printf("%s %s\n", "9a05:2f00:3f11::5f12::2", Cloak6("9a05:2f00:3f11::5f12::2").c_str());
214 printf("%s %s\n", "9a05:2f00:3f11::5a12::1", Cloak6("9a05:2f00:3f11::5a12::1").c_str());
215 printf("%s %s\n", "9a05:2f00:3f11::5a12::2", Cloak6("9a05:2f00:3f11::5a12::2").c_str());
216 printf("%s %s\n", "9a05:3f01:3f11::5f12::1", Cloak6("9a05:3f01:3f11::5f12::1").c_str());
217 printf("%s %s\n", "9a05:4f00:3f11::5f13::2", Cloak6("9a05:4f00:3f11::5f13::2").c_str());
218 printf("%s %s\n", "ffff:2f00:3f11::5f12::1", Cloak6("ffff:2f00:3f11::5f12::1").c_str());
219 printf("%s %s\n", "ffff:2f00:3f11::5f13::2", Cloak6("ffff:2f00:3f11::5f13::2").c_str());
226 ConfigReader Conf(ServerInstance);
227 key1 = key2 = key3 = key4 = 0;
228 key1 = Conf.ReadInteger("cloak","key1",0,false);
229 key2 = Conf.ReadInteger("cloak","key2",0,false);
230 key3 = Conf.ReadInteger("cloak","key3",0,false);
231 key4 = Conf.ReadInteger("cloak","key4",0,false);
233 prefix = Conf.ReadValue("cloak","prefix",0);
236 prefix = ServerInstance->Config->Network;
238 if (!key1 && !key2 && !key3 && !key4)
240 ModuleException ex("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
247 class ModuleCloaking : public Module
255 ModuleCloaking(InspIRCd* Me)
258 MD5Module = ServerInstance->FindModule("m_md5.so");
260 throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
262 /* Create new mode handler object */
263 cu = new CloakUser(ServerInstance, this, MD5Module);
265 /* Register it with the core */
266 ServerInstance->AddMode(cu, 'x');
271 virtual ~ModuleCloaking()
273 ServerInstance->Modes->DelMode(cu);
277 virtual Version GetVersion()
279 // returns the version number of the module to be
280 // listed in /MODULES
281 return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);
284 virtual void OnRehash(const std::string ¶meter)
289 void Implements(char* List)
291 List[I_OnRehash] = 1;
295 // stuff down here is the module-factory stuff. For basic modules you can ignore this.
297 class ModuleCloakingFactory : public ModuleFactory
300 ModuleCloakingFactory()
304 ~ModuleCloakingFactory()
308 virtual Module * CreateModule(InspIRCd* Me)
310 return new ModuleCloaking(Me);
316 extern "C" void * init_module( void )
318 return new ModuleCloakingFactory;