unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
cloak_md5.c (11631B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/cloak_md5.c 3 * (C) 2004-2017 Bram Matthys and The UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include "unrealircd.h" 24 25 static char *cloak_key1 = NULL, *cloak_key2 = NULL, *cloak_key3 = NULL; 26 static char cloak_checksum[64]; 27 static int nokeys = 1; 28 29 int CLOAK_IP_ONLY = 0; 30 31 #undef KEY1 32 #undef KEY2 33 #undef KEY3 34 #define KEY1 cloak_key1 35 #define KEY2 cloak_key2 36 #define KEY3 cloak_key3 37 38 char *hidehost(Client *client, char *host); 39 char *cloakcsum(); 40 int cloak_config_test(ConfigFile *, ConfigEntry *, int, int *); 41 int cloak_config_run(ConfigFile *, ConfigEntry *, int); 42 int cloak_config_posttest(int *); 43 44 static char *hidehost_ipv4(char *host); 45 static char *hidehost_ipv6(char *host); 46 static char *hidehost_normalhost(char *host); 47 static inline unsigned int downsample(char *i); 48 49 ModuleHeader MOD_HEADER = { 50 "cloak_md5", 51 "1.0", 52 "Old cloaking module (MD5)", 53 "UnrealIRCd Team", 54 "unrealircd-6", 55 }; 56 57 MOD_TEST() 58 { 59 if (!CallbackAddString(modinfo->handle, CALLBACKTYPE_CLOAK_KEY_CHECKSUM, cloakcsum)) 60 { 61 unreal_log(ULOG_ERROR, "config", "CLOAK_MODULE_DUPLICATE", NULL, 62 "cloak_md5: Error while trying to install callback.\n" 63 "Maybe you have multiple cloaking modules loaded? You can only load one!"); 64 return MOD_FAILED; 65 } 66 if (!CallbackAddString(modinfo->handle, CALLBACKTYPE_CLOAK_EX, hidehost)) 67 { 68 config_error("cloak_md5: Error while trying to install cloaking callback!"); 69 return MOD_FAILED; 70 } 71 HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, cloak_config_test); 72 HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, cloak_config_posttest); 73 return MOD_SUCCESS; 74 } 75 76 MOD_INIT() 77 { 78 MARK_AS_OFFICIAL_MODULE(modinfo); 79 HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, cloak_config_run); 80 return MOD_SUCCESS; 81 } 82 83 MOD_LOAD() 84 { 85 return MOD_SUCCESS; 86 } 87 88 MOD_UNLOAD() 89 { 90 if (cloak_key1) 91 { 92 safe_free(cloak_key1); 93 safe_free(cloak_key2); 94 safe_free(cloak_key3); 95 } 96 return MOD_SUCCESS; 97 } 98 99 static int check_badrandomness(char *key) 100 { 101 char gotlowcase=0, gotupcase=0, gotdigit=0; 102 char *p; 103 for (p=key; *p; p++) 104 if (islower(*p)) 105 gotlowcase = 1; 106 else if (isupper(*p)) 107 gotupcase = 1; 108 else if (isdigit(*p)) 109 gotdigit = 1; 110 111 if (gotlowcase && gotupcase && gotdigit) 112 return 0; 113 return 1; 114 } 115 116 117 int cloak_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 118 { 119 ConfigEntry *cep; 120 int keycnt = 0, errors = 0; 121 char *keys[3]; 122 123 if (type == CONFIG_SET) 124 { 125 /* set::cloak-method */ 126 if (!ce || !ce->name || strcmp(ce->name, "cloak-method")) 127 return 0; 128 129 if (!ce->value) 130 { 131 config_error("%s:%i: set::cloak-method: no method specified. The only supported methods are: 'ip' and 'host'", 132 ce->file->filename, ce->line_number); 133 errors++; 134 } else 135 if (strcmp(ce->value, "ip") && strcmp(ce->value, "host")) 136 { 137 config_error("%s:%i: set::cloak-method: unknown method '%s'. The only supported methods are: 'ip' and 'host'", 138 ce->file->filename, ce->line_number, ce->value); 139 errors++; 140 } 141 142 *errs = errors; 143 return errors ? -1 : 1; 144 } 145 146 if (type != CONFIG_CLOAKKEYS) 147 return 0; 148 149 nokeys = 0; 150 for (cep = ce->items; cep; cep = cep->next) 151 { 152 keycnt++; 153 if (check_badrandomness(cep->name)) 154 { 155 config_error("%s:%i: set::cloak-keys: (key %d) Keys should be mixed a-zA-Z0-9, " 156 "like \"a2JO6fh3Q6w4oN3s7\"", cep->file->filename, cep->line_number, keycnt); 157 errors++; 158 } 159 if (strlen(cep->name) < 5) 160 { 161 config_error("%s:%i: set::cloak-keys: (key %d) Each key should be at least 5 characters", 162 cep->file->filename, cep->line_number, keycnt); 163 errors++; 164 } 165 if (strlen(cep->name) > 100) 166 { 167 config_error("%s:%i: set::cloak-keys: (key %d) Each key should be less than 100 characters", 168 cep->file->filename, cep->line_number, keycnt); 169 errors++; 170 } 171 if (keycnt < 4) 172 keys[keycnt-1] = cep->name; 173 } 174 if (keycnt != 3) 175 { 176 config_error("%s:%i: set::cloak-keys: we want 3 values, not %i!", 177 ce->file->filename, ce->line_number, keycnt); 178 errors++; 179 } 180 if ((keycnt == 3) && (!strcmp(keys[0], keys[1]) || !strcmp(keys[1], keys[2]))) 181 { 182 config_error("%s:%i: set::cloak-keys: All your 3 keys should be RANDOM, they should not be equal", 183 ce->file->filename, ce->line_number); 184 errors++; 185 } 186 *errs = errors; 187 return errors ? -1 : 1; 188 } 189 190 int cloak_config_posttest(int *errs) 191 { 192 int errors = 0; 193 194 if (nokeys) 195 { 196 config_error("set::cloak-keys missing!"); 197 errors++; 198 } 199 200 *errs = errors; 201 return errors ? -1 : 1; 202 } 203 204 int cloak_config_run(ConfigFile *cf, ConfigEntry *ce, int type) 205 { 206 ConfigEntry *cep; 207 char buf[512], result[16]; 208 209 if (type == CONFIG_SET) 210 { 211 /* set::cloak-method */ 212 if (!ce || !ce->name || strcmp(ce->name, "cloak-method")) 213 return 0; 214 215 if (!strcmp(ce->value, "ip")) 216 CLOAK_IP_ONLY = 1; 217 218 return 0; 219 } 220 221 if (type != CONFIG_CLOAKKEYS) 222 return 0; 223 224 /* config test should ensure this goes fine... */ 225 cep = ce->items; 226 safe_strdup(cloak_key1, cep->name); 227 cep = cep->next; 228 safe_strdup(cloak_key2, cep->name); 229 cep = cep->next; 230 safe_strdup(cloak_key3, cep->name); 231 232 /* Calculate checksum */ 233 ircsnprintf(buf, sizeof(buf), "%s:%s:%s", KEY1, KEY2, KEY3); 234 DoMD5(result, buf, strlen(buf)); 235 ircsnprintf(cloak_checksum, sizeof(cloak_checksum), 236 "MD5:%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x", 237 (u_int)(result[0] & 0xf), (u_int)(result[0] >> 4), 238 (u_int)(result[1] & 0xf), (u_int)(result[1] >> 4), 239 (u_int)(result[2] & 0xf), (u_int)(result[2] >> 4), 240 (u_int)(result[3] & 0xf), (u_int)(result[3] >> 4), 241 (u_int)(result[4] & 0xf), (u_int)(result[4] >> 4), 242 (u_int)(result[5] & 0xf), (u_int)(result[5] >> 4), 243 (u_int)(result[6] & 0xf), (u_int)(result[6] >> 4), 244 (u_int)(result[7] & 0xf), (u_int)(result[7] >> 4), 245 (u_int)(result[8] & 0xf), (u_int)(result[8] >> 4), 246 (u_int)(result[9] & 0xf), (u_int)(result[9] >> 4), 247 (u_int)(result[10] & 0xf), (u_int)(result[10] >> 4), 248 (u_int)(result[11] & 0xf), (u_int)(result[11] >> 4), 249 (u_int)(result[12] & 0xf), (u_int)(result[12] >> 4), 250 (u_int)(result[13] & 0xf), (u_int)(result[13] >> 4), 251 (u_int)(result[14] & 0xf), (u_int)(result[14] >> 4), 252 (u_int)(result[15] & 0xf), (u_int)(result[15] >> 4)); 253 return 1; 254 } 255 256 char *hidehost(Client *client, char *host) 257 { 258 char *p; 259 int host_type; 260 261 if (CLOAK_IP_ONLY) 262 host = GetIP(client); 263 264 host_type = is_valid_ip(host); 265 266 if (host_type == 4) 267 return hidehost_ipv4(host); 268 else if (host_type == 6) 269 return hidehost_ipv6(host); 270 else 271 return hidehost_normalhost(host); 272 } 273 274 char *cloakcsum() 275 { 276 return cloak_checksum; 277 } 278 279 /** Downsamples a 128bit result to 32bits (md5 -> unsigned int) */ 280 static inline unsigned int downsample(char *i) 281 { 282 char r[4]; 283 284 r[0] = i[0] ^ i[1] ^ i[2] ^ i[3]; 285 r[1] = i[4] ^ i[5] ^ i[6] ^ i[7]; 286 r[2] = i[8] ^ i[9] ^ i[10] ^ i[11]; 287 r[3] = i[12] ^ i[13] ^ i[14] ^ i[15]; 288 289 return ( ((unsigned int)r[0] << 24) + 290 ((unsigned int)r[1] << 16) + 291 ((unsigned int)r[2] << 8) + 292 (unsigned int)r[3]); 293 } 294 295 static char *hidehost_ipv4(char *host) 296 { 297 unsigned int a, b, c, d; 298 static char buf[512], res[512], res2[512], result[128]; 299 unsigned long n; 300 unsigned int alpha, beta, gamma; 301 302 /* 303 * Output: ALPHA.BETA.GAMMA.IP 304 * ALPHA is unique for a.b.c.d 305 * BETA is unique for a.b.c.* 306 * GAMMA is unique for a.b.* 307 * We cloak like this: 308 * ALPHA = downsample(md5(md5("KEY2:A.B.C.D:KEY3")+"KEY1")); 309 * BETA = downsample(md5(md5("KEY3:A.B.C:KEY1")+"KEY2")); 310 * GAMMA = downsample(md5(md5("KEY1:A.B:KEY2")+"KEY3")); 311 */ 312 sscanf(host, "%u.%u.%u.%u", &a, &b, &c, &d); 313 314 /* ALPHA... */ 315 ircsnprintf(buf, sizeof(buf), "%s:%s:%s", KEY2, host, KEY3); 316 DoMD5(res, buf, strlen(buf)); 317 strlcpy(res+16, KEY1, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 318 n = strlen(res+16) + 16; 319 DoMD5(res2, res, n); 320 alpha = downsample(res2); 321 322 /* BETA... */ 323 ircsnprintf(buf, sizeof(buf), "%s:%d.%d.%d:%s", KEY3, a, b, c, KEY1); 324 DoMD5(res, buf, strlen(buf)); 325 strlcpy(res+16, KEY2, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 326 n = strlen(res+16) + 16; 327 DoMD5(res2, res, n); 328 beta = downsample(res2); 329 330 /* GAMMA... */ 331 ircsnprintf(buf, sizeof(buf), "%s:%d.%d:%s", KEY1, a, b, KEY2); 332 DoMD5(res, buf, strlen(buf)); 333 strlcpy(res+16, KEY3, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 334 n = strlen(res+16) + 16; 335 DoMD5(res2, res, n); 336 gamma = downsample(res2); 337 338 ircsnprintf(result, sizeof(result), "%X.%X.%X.IP", alpha, beta, gamma); 339 return result; 340 } 341 342 static char *hidehost_ipv6(char *host) 343 { 344 unsigned int a, b, c, d, e, f, g, h; 345 static char buf[512], res[512], res2[512], result[128]; 346 unsigned long n; 347 unsigned int alpha, beta, gamma; 348 349 /* 350 * Output: ALPHA:BETA:GAMMA:IP 351 * ALPHA is unique for a:b:c:d:e:f:g:h 352 * BETA is unique for a:b:c:d:e:f:g 353 * GAMMA is unique for a:b:c:d 354 * We cloak like this: 355 * ALPHA = downsample(md5(md5("KEY2:a:b:c:d:e:f:g:h:KEY3")+"KEY1")); 356 * BETA = downsample(md5(md5("KEY3:a:b:c:d:e:f:g:KEY1")+"KEY2")); 357 * GAMMA = downsample(md5(md5("KEY1:a:b:c:d:KEY2")+"KEY3")); 358 */ 359 sscanf(host, "%x:%x:%x:%x:%x:%x:%x:%x", 360 &a, &b, &c, &d, &e, &f, &g, &h); 361 362 /* ALPHA... */ 363 ircsnprintf(buf, sizeof(buf), "%s:%s:%s", KEY2, host, KEY3); 364 DoMD5(res, buf, strlen(buf)); 365 strlcpy(res+16, KEY1, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 366 n = strlen(res+16) + 16; 367 DoMD5(res2, res, n); 368 alpha = downsample(res2); 369 370 /* BETA... */ 371 ircsnprintf(buf, sizeof(buf), "%s:%x:%x:%x:%x:%x:%x:%x:%s", KEY3, a, b, c, d, e, f, g, KEY1); 372 DoMD5(res, buf, strlen(buf)); 373 strlcpy(res+16, KEY2, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 374 n = strlen(res+16) + 16; 375 DoMD5(res2, res, n); 376 beta = downsample(res2); 377 378 /* GAMMA... */ 379 ircsnprintf(buf, sizeof(buf), "%s:%x:%x:%x:%x:%s", KEY1, a, b, c, d, KEY2); 380 DoMD5(res, buf, strlen(buf)); 381 strlcpy(res+16, KEY3, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 382 n = strlen(res+16) + 16; 383 DoMD5(res2, res, n); 384 gamma = downsample(res2); 385 386 ircsnprintf(result, sizeof(result), "%X:%X:%X:IP", alpha, beta, gamma); 387 return result; 388 } 389 390 static char *hidehost_normalhost(char *host) 391 { 392 char *p; 393 static char buf[512], res[512], res2[512], result[HOSTLEN+1]; 394 unsigned int alpha, n; 395 396 ircsnprintf(buf, sizeof(buf), "%s:%s:%s", KEY1, host, KEY2); 397 DoMD5(res, buf, strlen(buf)); 398 strlcpy(res+16, KEY3, sizeof(res)-16); /* first 16 bytes are filled, append our key.. */ 399 n = strlen(res+16) + 16; 400 DoMD5(res2, res, n); 401 alpha = downsample(res2); 402 403 for (p = host; *p; p++) 404 if (*p == '.') 405 if (isalpha(*(p + 1))) 406 break; 407 408 if (*p) 409 { 410 unsigned int len; 411 p++; 412 ircsnprintf(result, sizeof(result), "%s-%X.", CLOAK_PREFIX, alpha); 413 len = strlen(result) + strlen(p); 414 if (len <= HOSTLEN) 415 strlcat(result, p, sizeof(result)); 416 else 417 strlcat(result, p + (len - HOSTLEN), sizeof(result)); 418 } else 419 ircsnprintf(result, sizeof(result), "%s-%X", CLOAK_PREFIX, alpha); 420 421 return result; 422 }