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 }