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 }