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 */
28 static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};
30 /** Handles user mode +x
32 class CloakUser : public ModeHandler
44 CloakUser(InspIRCd* Instance, Module* Source, Module* MD5) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), MD5Provider(MD5)
48 ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
50 /* Only opers can change other users modes */
51 if ((source != dest) && (!*source->oper))
52 return MODEACTION_DENY;
54 /* For remote clients, we dont take any action, we just allow it.
55 * The local server where they are will set their cloak instead.
58 return MODEACTION_ALLOW;
62 if(!dest->IsModeSet('x'))
64 /* The mode is being turned on - so attempt to
65 * allocate the user a cloaked host using a non-reversible
66 * algorithm (its simple, but its non-reversible so the
67 * simplicity doesnt really matter). This algorithm
68 * will not work if the user has only one level of domain
69 * naming in their hostname (e.g. if they are on a lan or
70 * are connecting via localhost) -- this doesnt matter much.
73 if (strchr(dest->host,'.') || strchr(dest->host,':'))
75 /* InspIRCd users have two hostnames; A displayed
76 * hostname which can be modified by modules (e.g.
77 * to create vhosts, implement chghost, etc) and a
78 * 'real' hostname which you shouldnt write to.
81 char* n = strstr(dest->host,".");
83 n = strstr(dest->host,":");
89 std::string hostcloak = prefix + "-" + MD5SumRequest(Sender, MD5Provider, dest->host).Send() + a;
91 /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
92 * according to the DNS RFC) then tough titty, they get cloaked as an IP.
93 * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie
97 if ((insp_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
99 // if they have a hostname, make something appropriate
104 b = ((b.find(':') == std::string::npos) ? Cloak4(dest->host) : Cloak6(dest->host));
106 ServerInstance->Log(DEBUG,"cloak: allocated "+b);
107 dest->ChangeDisplayedHost(b.c_str());
110 dest->SetMode('x',true);
111 return MODEACTION_ALLOW;
116 if (dest->IsModeSet('x'))
118 /* User is removing the mode, so just restore their real host
119 * and make it match the displayed one.
121 dest->ChangeDisplayedHost(dest->host);
122 dest->SetMode('x',false);
123 return MODEACTION_ALLOW;
127 return MODEACTION_DENY;
130 std::string Cloak4(const char* ip)
132 unsigned int iv[] = { key1, key2, key3, key4 };
133 irc::sepstream seps(ip, '.');
134 std::string ra1, ra2, ra3, ra4;
136 std::string octet1 = seps.GetToken();
137 std::string octet2 = seps.GetToken();
138 std::string octet3 = seps.GetToken();
139 std::string octet4 = seps.GetToken();
140 i1 = atoi(octet1.c_str());
141 i2 = atoi(octet2.c_str());
142 i3 = atoi(octet3.c_str());
143 i4 = atoi(octet4.c_str());
144 octet4 = octet1 + "." + octet2 + "." + octet3 + "." + octet4;
145 octet3 = octet1 + "." + octet2 + "." + octet3;
146 octet2 = octet1 + "." + octet2;
148 MD5ResetRequest(Sender, MD5Provider).Send();
149 MD5KeyRequest(Sender, MD5Provider, iv).Send();
151 MD5HexRequest(Sender, MD5Provider, xtab[(key1+i1) % 4]).Send();
152 ra1 = std::string(MD5SumRequest(Sender, MD5Provider, octet1).Send()).substr(0,6);
154 MD5HexRequest(Sender, MD5Provider, xtab[(key2+i2) % 4]).Send();
155 ra2 = std::string(MD5SumRequest(Sender, MD5Provider, octet2).Send()).substr(0,6);
157 MD5HexRequest(Sender, MD5Provider, xtab[(key3+i3) % 4]).Send();
158 ra3 = std::string(MD5SumRequest(Sender, MD5Provider, octet3).Send()).substr(0,6);
160 MD5HexRequest(Sender, MD5Provider, xtab[(key4+i4) % 4]).Send();
161 ra4 = std::string(MD5SumRequest(Sender, MD5Provider, octet4).Send()).substr(0,6);
163 /* This is safe as we know the length generated by our genhash is always 16 */
164 return std::string().append(ra1).append(".").append(ra2).append(".").append(ra3).append(".").append(ra4);
167 std::string Cloak6(const char* ip)
169 unsigned int iv[] = { key1, key2, key3, key4 };
170 std::vector<std::string> hashies;
171 std::string item = "";
174 MD5ResetRequest(Sender, MD5Provider).Send();
175 MD5KeyRequest(Sender, MD5Provider, iv).Send();
177 for (const char* input = ip; *input; input++)
180 if (item.length() > 5)
182 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
183 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
190 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
191 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
194 return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
197 /* XXX: Uncomment and call to use the test suite
200 printf("%s %s\n", "192.168.1.1", Cloak4("192.168.1.1").c_str());
201 printf("%s %s\n", "192.168.1.2", Cloak4("192.168.1.2").c_str());
202 printf("%s %s\n", "192.168.10.1", Cloak4("192.168.10.1").c_str());
203 printf("%s %s\n", "192.168.10.1", Cloak4("192.168.10.2").c_str());
204 printf("%s %s\n", "192.169.1.1", Cloak4("192.169.1.1").c_str());
205 printf("%s %s\n", "192.169.2.1", Cloak4("192.169.2.1").c_str());
206 printf("%s %s\n", "200.168.1.1", Cloak4("200.168.1.1").c_str());
207 printf("%s %s\n", "200.168.1.3", Cloak4("200.168.1.3").c_str());
208 printf("%s %s\n", "200.168.3.3", Cloak4("200.168.3.3").c_str());
209 printf("%s %s\n", "200.169.4.3", Cloak4("200.169.4.3").c_str());
211 printf("%s %s\n", "9a05:2f00:3f11::5f12::1", Cloak6("9a05:2f00:3f11::5f12::1").c_str());
212 printf("%s %s\n", "9a05:2f00:3f11::5f12::2", Cloak6("9a05:2f00:3f11::5f12::2").c_str());
213 printf("%s %s\n", "9a05:2f00:3f11::5a12::1", Cloak6("9a05:2f00:3f11::5a12::1").c_str());
214 printf("%s %s\n", "9a05:2f00:3f11::5a12::2", Cloak6("9a05:2f00:3f11::5a12::2").c_str());
215 printf("%s %s\n", "9a05:3f01:3f11::5f12::1", Cloak6("9a05:3f01:3f11::5f12::1").c_str());
216 printf("%s %s\n", "9a05:4f00:3f11::5f13::2", Cloak6("9a05:4f00:3f11::5f13::2").c_str());
217 printf("%s %s\n", "ffff:2f00:3f11::5f12::1", Cloak6("ffff:2f00:3f11::5f12::1").c_str());
218 printf("%s %s\n", "ffff:2f00:3f11::5f13::2", Cloak6("ffff:2f00:3f11::5f13::2").c_str());
225 ConfigReader Conf(ServerInstance);
226 key1 = key2 = key3 = key4 = 0;
227 key1 = Conf.ReadInteger("cloak","key1",0,false);
228 key2 = Conf.ReadInteger("cloak","key2",0,false);
229 key3 = Conf.ReadInteger("cloak","key3",0,false);
230 key4 = Conf.ReadInteger("cloak","key4",0,false);
232 prefix = Conf.ReadValue("cloak","prefix",0);
235 prefix = ServerInstance->Config->Network;
237 if (!key1 && !key2 && !key3 && !key4)
239 ModuleException ex("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
246 class ModuleCloaking : public Module
254 ModuleCloaking(InspIRCd* Me)
257 MD5Module = ServerInstance->FindModule("m_md5.so");
259 throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
261 /* Create new mode handler object */
262 cu = new CloakUser(ServerInstance, this, MD5Module);
264 /* Register it with the core */
265 ServerInstance->AddMode(cu, 'x');
270 virtual ~ModuleCloaking()
272 ServerInstance->Modes->DelMode(cu);
276 virtual Version GetVersion()
278 // returns the version number of the module to be
279 // listed in /MODULES
280 return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);
283 virtual void OnRehash(const std::string ¶meter)
288 void Implements(char* List)
290 List[I_OnRehash] = 1;
294 // stuff down here is the module-factory stuff. For basic modules you can ignore this.
296 class ModuleCloakingFactory : public ModuleFactory
299 ModuleCloakingFactory()
303 ~ModuleCloakingFactory()
307 virtual Module * CreateModule(InspIRCd* Me)
309 return new ModuleCloaking(Me);
315 extern "C" void * init_module( void )
317 return new ModuleCloakingFactory;