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