mirror of https://github.com/pissnet/pissircd.git
920 lines
21 KiB
C
920 lines
21 KiB
C
/*
|
|
* IRC - Internet Relay Chat, antirandom.c
|
|
* (C) Copyright 2004-2016, Bram Matthys (Syzop) <syzop@vulnscan.org>
|
|
*
|
|
* Contains ideas from Keith Dunnett <keith@dunnett.org>
|
|
* Most of the detection mechanisms come from SpamAssassin FVGT_Tripwire.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "unrealircd.h"
|
|
|
|
ModuleHeader MOD_HEADER
|
|
= {
|
|
"antirandom",
|
|
"1.5",
|
|
"Detect and ban users with random names",
|
|
"UnrealIRCd Team",
|
|
"unrealircd-6",
|
|
};
|
|
|
|
#ifndef MAX
|
|
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
|
#endif
|
|
|
|
/* "<char1><char2>" followed by "<rest>" */
|
|
static char *triples_txt[] = {
|
|
"aj", "fqtvxz",
|
|
"aq", "deghjkmnprtxyz",
|
|
"av", "bfhjqwxz",
|
|
"az", "jwx",
|
|
"bd", "bghjkmpqvxz",
|
|
"bf", "bcfgjknpqvwxyz",
|
|
"bg", "bdfghjkmnqstvxz",
|
|
"bh", "bfhjkmnqvwxz",
|
|
"bj", "bcdfghjklmpqtvwxyz",
|
|
"bk", "dfjkmqrvwxyz",
|
|
"bl", "bgpqwxz",
|
|
"bm", "bcdflmnqz",
|
|
"bn", "bghjlmnpqtvwx",
|
|
"bp", "bfgjknqvxz",
|
|
"bq", "bcdefghijklmnopqrstvwxyz",
|
|
"bt", "dgjkpqtxz",
|
|
"bv", "bfghjklnpqsuvwxz",
|
|
"bw", "bdfjknpqsuwxyz",
|
|
"bx", "abcdfghijklmnopqtuvwxyz",
|
|
"bz", "bcdfgjklmnpqrstvwxz",
|
|
"cb", "bfghjkpqyz",
|
|
"cc", "gjqxz",
|
|
"cd", "hjkqvwxz",
|
|
"cf", "gjknqvwyz",
|
|
"cg", "bdfgjkpqvz",
|
|
"cl", "fghjmpqxz",
|
|
"cm", "bjkqv",
|
|
"cn", "bghjkpqwxz",
|
|
"cp", "gjkvxyz",
|
|
"cq", "abcdefghijklmnopqsvwxyz",
|
|
"cr", "gjqx",
|
|
"cs", "gjxz",
|
|
"cv", "bdfghjklmnquvwxyz",
|
|
"cx", "abdefghjklmnpqrstuvwxyz",
|
|
"cy", "jqy",
|
|
"cz", "bcdfghjlpqrtvwxz",
|
|
"db", "bdgjnpqtxz",
|
|
"dc", "gjqxz",
|
|
"dd", "gqz",
|
|
"df", "bghjknpqvxyz",
|
|
"dg", "bfgjqvxz",
|
|
"dh", "bfkmnqwxz",
|
|
"dj", "bdfghjklnpqrwxz",
|
|
"dk", "cdhjkpqrtuvwxz",
|
|
"dl", "bfhjknqwxz",
|
|
"dm", "bfjnqw",
|
|
"dn", "fgjkmnpqvwz",
|
|
"dp", "bgjkqvxz",
|
|
"dq", "abcefghijkmnopqtvwxyz",
|
|
"dr", "bfkqtvx",
|
|
"dt", "qtxz",
|
|
"dv", "bfghjknqruvwyz",
|
|
"dw", "cdfjkmnpqsvwxz",
|
|
"dx", "abcdeghjklmnopqrsuvwxyz",
|
|
"dy", "jyz",
|
|
"dz", "bcdfgjlnpqrstvxz",
|
|
"eb", "jqx",
|
|
"eg", "cjvxz",
|
|
"eh", "hxz",
|
|
"ej", "fghjpqtwxyz",
|
|
"ek", "jqxz",
|
|
"ep", "jvx",
|
|
"eq", "bcghijkmotvxyz",
|
|
"ev", "bfpq",
|
|
"fc", "bdjkmnqvxz",
|
|
"fd", "bgjklqsvyz",
|
|
"fg", "fgjkmpqtvwxyz",
|
|
"fh", "bcfghjkpqvwxz",
|
|
"fj", "bcdfghijklmnpqrstvwxyz",
|
|
"fk", "bcdfghjkmpqrstvwxz",
|
|
"fl", "fjkpqxz",
|
|
"fm", "dfhjlmvwxyz",
|
|
"fn", "bdfghjklnqrstvwxz",
|
|
"fp", "bfjknqtvwxz",
|
|
"fq", "abcefghijklmnopqrstvwxyz",
|
|
"fr", "nqxz",
|
|
"fs", "gjxz",
|
|
"ft", "jqx",
|
|
"fv", "bcdfhjklmnpqtuvwxyz",
|
|
"fw", "bcfgjklmpqstuvwxyz",
|
|
"fx", "bcdfghjklmnpqrstvwxyz",
|
|
"fy", "ghjpquvxy",
|
|
"fz", "abcdfghjklmnpqrtuvwxyz",
|
|
"gb", "bcdknpqvwx",
|
|
"gc", "gjknpqwxz",
|
|
"gd", "cdfghjklmqtvwxz",
|
|
"gf", "bfghjkmnpqsvwxyz",
|
|
"gg", "jkqvxz",
|
|
"gj", "bcdfghjklmnpqrstvwxyz",
|
|
"gk", "bcdfgjkmpqtvwxyz",
|
|
"gl", "fgjklnpqwxz",
|
|
"gm", "dfjkmnqvxz",
|
|
"gn", "jkqvxz",
|
|
"gp", "bjknpqtwxyz",
|
|
"gq", "abcdefghjklmnopqrsvwxyz",
|
|
"gr", "jkqt",
|
|
"gt", "fjknqvx",
|
|
"gu", "qwx",
|
|
"gv", "bcdfghjklmpqstvwxyz",
|
|
"gw", "bcdfgjknpqtvwxz",
|
|
"gx", "abcdefghjklmnopqrstvwxyz",
|
|
"gy", "jkqxy",
|
|
"gz", "bcdfgjklmnopqrstvxyz",
|
|
"hb", "bcdfghjkqstvwxz",
|
|
"hc", "cjknqvwxz",
|
|
"hd", "fgjnpvz",
|
|
"hf", "bfghjkmnpqtvwxyz",
|
|
"hg", "bcdfgjknpqsxyz",
|
|
"hh", "bcgklmpqrtvwxz",
|
|
"hj", "bcdfgjkmpqtvwxyz",
|
|
"hk", "bcdgkmpqrstvwxz",
|
|
"hl", "jxz",
|
|
"hm", "dhjqrvwxz",
|
|
"hn", "jrxz",
|
|
"hp", "bjkmqvwxyz",
|
|
"hq", "abcdefghijklmnopqrstvwyz",
|
|
"hr", "cjqx",
|
|
"hs", "jqxz",
|
|
"hv", "bcdfgjklmnpqstuvwxz",
|
|
"hw", "bcfgjklnpqsvwxz",
|
|
"hx", "abcdefghijklmnopqrstuvwxyz",
|
|
"hz", "bcdfghjklmnpqrstuvwxz",
|
|
"ib", "jqx",
|
|
"if", "jqvwz",
|
|
"ih", "bgjqx",
|
|
"ii", "bjqxy",
|
|
"ij", "cfgqxy",
|
|
"ik", "bcfqx",
|
|
"iq", "cdefgjkmnopqtvxyz",
|
|
"iu", "hiwxy",
|
|
"iv", "cfgmqx",
|
|
"iw", "dgjkmnpqtvxz",
|
|
"ix", "jkqrxz",
|
|
"iy", "bcdfghjklpqtvwx",
|
|
"jb", "bcdghjklmnopqrtuvwxyz",
|
|
"jc", "cfgjkmnopqvwxy",
|
|
"jd", "cdfghjlmnpqrtvwx",
|
|
"jf", "abcdfghjlnopqrtuvwxyz",
|
|
"jg", "bcdfghijklmnopqstuvwxyz",
|
|
"jh", "bcdfghjklmnpqrxyz",
|
|
"jj", "bcdfghjklmnopqrstuvwxyz",
|
|
"jk", "bcdfghjknqrtwxyz",
|
|
"jl", "bcfghjmnpqrstuvwxyz",
|
|
"jm", "bcdfghiklmnqrtuvwyz",
|
|
"jn", "bcfjlmnpqsuvwxz",
|
|
"jp", "bcdfhijkmpqstvwxyz",
|
|
"jq", "abcdefghijklmnopqrstuvwxyz",
|
|
"jr", "bdfhjklpqrstuvwxyz",
|
|
"js", "bfgjmoqvxyz",
|
|
"jt", "bcdfghjlnpqrtvwxz",
|
|
"jv", "abcdfghijklpqrstvwxyz",
|
|
"jw", "bcdefghijklmpqrstuwxyz",
|
|
"jx", "abcdefghijklmnopqrstuvwxyz",
|
|
"jy", "bcdefghjkpqtuvwxyz",
|
|
"jz", "bcdfghijklmnopqrstuvwxyz",
|
|
"kb", "bcdfghjkmqvwxz",
|
|
"kc", "cdfgjknpqtwxz",
|
|
"kd", "bfghjklmnpqsvwxyz",
|
|
"kf", "bdfghjkmnpqsvwxyz",
|
|
"kg", "cghjkmnqtvwxyz",
|
|
"kh", "cfghjkqx",
|
|
"kj", "bcdfghjkmnpqrstwxyz",
|
|
"kk", "bcdfgjmpqswxz",
|
|
"kl", "cfghlmqstwxz",
|
|
"km", "bdfghjknqrstwxyz",
|
|
"kn", "bcdfhjklmnqsvwxz",
|
|
"kp", "bdfgjkmpqvxyz",
|
|
"kq", "abdefghijklmnopqrstvwxyz",
|
|
"kr", "bcdfghjmqrvwx",
|
|
"ks", "jqx",
|
|
"kt", "cdfjklqvx",
|
|
"ku", "qux",
|
|
"kv", "bcfghjklnpqrstvxyz",
|
|
"kw", "bcdfgjklmnpqsvwxz",
|
|
"kx", "abcdefghjklmnopqrstuvwxyz",
|
|
"ky", "vxy",
|
|
"kz", "bcdefghjklmnpqrstuvwxyz",
|
|
"lb", "cdgkqtvxz",
|
|
"lc", "bqx",
|
|
"lg", "cdfgpqvxz",
|
|
"lh", "cfghkmnpqrtvx",
|
|
"lk", "qxz",
|
|
"ln", "cfjqxz",
|
|
"lp", "jkqxz",
|
|
"lq", "bcdefhijklmopqrstvwxyz",
|
|
"lr", "dfgjklmpqrtvwx",
|
|
"lv", "bcfhjklmpwxz",
|
|
"lw", "bcdfgjknqxz",
|
|
"lx", "bcdfghjklmnpqrtuwz",
|
|
"lz", "cdjptvxz",
|
|
"mb", "qxz",
|
|
"md", "hjkpvz",
|
|
"mf", "fkpqvwxz",
|
|
"mg", "cfgjnpqsvwxz",
|
|
"mh", "bchjkmnqvx",
|
|
"mj", "bcdfghjknpqrstvwxyz",
|
|
"mk", "bcfgklmnpqrvwxz",
|
|
"ml", "jkqz",
|
|
"mm", "qvz",
|
|
"mn", "fhjkqxz",
|
|
"mq", "bdefhjklmnopqtwxyz",
|
|
"mr", "jklqvwz",
|
|
"mt", "jkq",
|
|
"mv", "bcfghjklmnqtvwxz",
|
|
"mw", "bcdfgjklnpqsuvwxyz",
|
|
"mx", "abcefghijklmnopqrstvwxyz",
|
|
"mz", "bcdfghjkmnpqrstvwxz",
|
|
"nb", "hkmnqxz",
|
|
"nf", "bghqvxz",
|
|
"nh", "fhjkmqtvxz",
|
|
"nk", "qxz",
|
|
"nl", "bghjknqvwxz",
|
|
"nm", "dfghjkqtvwxz",
|
|
"np", "bdjmqwxz",
|
|
"nq", "abcdfghjklmnopqrtvwxyz",
|
|
"nr", "bfjkqstvx",
|
|
"nv", "bcdfgjkmnqswxz",
|
|
"nw", "dgjpqvxz",
|
|
"nx", "abfghjknopuyz",
|
|
"nz", "cfqrxz",
|
|
"oc", "fjvw",
|
|
"og", "qxz",
|
|
"oh", "fqxz",
|
|
"oj", "bfhjmqrswxyz",
|
|
"ok", "qxz",
|
|
"oq", "bcdefghijklmnopqrstvwxyz",
|
|
"ov", "bfhjqwx",
|
|
"oy", "qxy",
|
|
"oz", "fjpqtvx",
|
|
"pb", "fghjknpqvwz",
|
|
"pc", "gjq",
|
|
"pd", "bgjkvwxz",
|
|
"pf", "hjkmqtvwyz",
|
|
"pg", "bdfghjkmqsvwxyz",
|
|
"ph", "kqvx",
|
|
"pk", "bcdfhjklmpqrvx",
|
|
"pl", "ghkqvwx",
|
|
"pm", "bfhjlmnqvwyz",
|
|
"pn", "fjklmnqrtvwz",
|
|
"pp", "gqwxz",
|
|
"pq", "abcdefghijklmnopqstvwxyz",
|
|
"pr", "hjkqrwx",
|
|
"pt", "jqxz",
|
|
"pv", "bdfghjklquvwxyz",
|
|
"pw", "fjkmnpqsuvwxz",
|
|
"px", "abcdefghijklmnopqrstuvwxyz",
|
|
"pz", "bdefghjklmnpqrstuvwxyz",
|
|
"qa", "ceghkopqxy",
|
|
"qb", "bcdfghjklmnqrstuvwxyz",
|
|
"qc", "abcdfghijklmnopqrstuvwxyz",
|
|
"qd", "defghijklmpqrstuvwxyz",
|
|
"qe", "abceghjkmopquwxyz",
|
|
"qf", "abdfghijklmnopqrstuvwxyz",
|
|
"qg", "abcdefghijklmnopqrtuvwxz",
|
|
"qh", "abcdefghijklmnopqrstuvwxyz",
|
|
"qi", "efgijkmpwx",
|
|
"qj", "abcdefghijklmnopqrstuvwxyz",
|
|
"qk", "abcdfghijklmnopqrsuvwxyz",
|
|
"ql", "abcefghjklmnopqrtuvwxyz",
|
|
"qm", "bdehijklmnoqrtuvxyz",
|
|
"qn", "bcdefghijklmnoqrtuvwxyz",
|
|
"qo", "abcdefgijkloqstuvwxyz",
|
|
"qp", "abcdefghijkmnopqrsuvwxyz",
|
|
"qq", "bcdefghijklmnopstwxyz",
|
|
"qr", "bdefghijklmnoqruvwxyz",
|
|
"qs", "bcdefgijknqruvwxz",
|
|
"qt", "befghjklmnpqtuvwxz",
|
|
"qu", "cfgjkpwz",
|
|
"qv", "abdefghjklmnopqrtuvwxyz",
|
|
"qw", "bcdfghijkmnopqrstuvwxyz",
|
|
"qx", "abcdefghijklmnopqrstuvwxyz",
|
|
"qy", "abcdefghjklmnopqrstuvwxyz",
|
|
"qz", "abcdefghijklmnopqrstuvwxyz",
|
|
"rb", "fxz",
|
|
"rg", "jvxz",
|
|
"rh", "hjkqrxz",
|
|
"rj", "bdfghjklmpqrstvwxz",
|
|
"rk", "qxz",
|
|
"rl", "jnq",
|
|
"rp", "jxz",
|
|
"rq", "bcdefghijklmnopqrtvwxy",
|
|
"rr", "jpqxz",
|
|
"rv", "bcdfghjmpqrvwxz",
|
|
"rw", "bfgjklqsvxz",
|
|
"rx", "bcdfgjkmnopqrtuvwxz",
|
|
"rz", "djpqvxz",
|
|
"sb", "kpqtvxz",
|
|
"sd", "jqxz",
|
|
"sf", "bghjkpqw",
|
|
"sg", "cgjkqvwxz",
|
|
"sj", "bfghjkmnpqrstvwxz",
|
|
"sk", "qxz",
|
|
"sl", "gjkqwxz",
|
|
"sm", "fkqwxz",
|
|
"sn", "dhjknqvwxz",
|
|
"sq", "bfghjkmopstvwxz",
|
|
"sr", "jklqrwxz",
|
|
"sv", "bfhjklmnqtwxyz",
|
|
"sw", "jkpqvwxz",
|
|
"sx", "bcdefghjklmnopqrtuvwxyz",
|
|
"sy", "qxy",
|
|
"sz", "bdfgjpqsvxz",
|
|
"tb", "cghjkmnpqtvwx",
|
|
"tc", "jnqvx",
|
|
"td", "bfgjkpqtvxz",
|
|
"tf", "ghjkqvwyz",
|
|
"tg", "bdfghjkmpqsx",
|
|
"tj", "bdfhjklmnpqstvwxyz",
|
|
"tk", "bcdfghjklmpqvwxz",
|
|
"tl", "jkqwxz",
|
|
"tm", "bknqtwxz",
|
|
"tn", "fhjkmqvwxz",
|
|
"tp", "bjpqvwxz",
|
|
"tq", "abdefhijklmnopqrstvwxyz",
|
|
"tr", "gjqvx",
|
|
"tv", "bcfghjknpquvwxz",
|
|
"tw", "bcdfjknqvz",
|
|
"tx", "bcdefghjklmnopqrsuvwxz",
|
|
"tz", "jqxz",
|
|
"uc", "fjmvx",
|
|
"uf", "jpqvx",
|
|
"ug", "qvx",
|
|
"uh", "bcgjkpvxz",
|
|
"uj", "wbfghklmqvwx",
|
|
"uk", "fgqxz",
|
|
"uq", "bcdfghijklmnopqrtwxyz",
|
|
"uu", "fijkqvwyz",
|
|
"uv", "bcdfghjkmpqtwxz",
|
|
"uw", "dgjnquvxyz",
|
|
"ux", "jqxz",
|
|
"uy", "jqxyz",
|
|
"uz", "fgkpqrx",
|
|
"vb", "bcdfhijklmpqrtuvxyz",
|
|
"vc", "bgjklnpqtvwxyz",
|
|
"vd", "bdghjklnqvwxyz",
|
|
"vf", "bfghijklmnpqtuvxz",
|
|
"vg", "bcdgjkmnpqtuvwxyz",
|
|
"vh", "bcghijklmnpqrtuvwxyz",
|
|
"vj", "abcdfghijklmnpqrstuvwxyz",
|
|
"vk", "bcdefgjklmnpqruvwxyz",
|
|
"vl", "hjkmpqrvwxz",
|
|
"vm", "bfghjknpquvxyz",
|
|
"vn", "bdhjkmnpqrtuvwxz",
|
|
"vp", "bcdeghjkmopqtuvwyz",
|
|
"vq", "abcdefghijklmnopqrstvwxyz",
|
|
"vr", "fghjknqrtvwxz",
|
|
"vs", "dfgjmqz",
|
|
"vt", "bdfgjklmnqtx",
|
|
"vu", "afhjquwxy",
|
|
"vv", "cdfghjkmnpqrtuwxz",
|
|
"vw", "abcdefghijklmnopqrtuvwxyz",
|
|
"vx", "abcefghjklmnopqrstuvxyz",
|
|
"vy", "oqx",
|
|
"vz", "abcdefgjklmpqrstvwxyz",
|
|
"wb", "bdfghjpqtvxz",
|
|
"wc", "bdfgjkmnqvwx",
|
|
"wd", "dfjpqvxz",
|
|
"wf", "cdghjkmqvwxyz",
|
|
"wg", "bcdfgjknpqtvwxyz",
|
|
"wh", "cdghjklpqvwxz",
|
|
"wj", "bfghijklmnpqrstvwxyz",
|
|
"wk", "cdfgjkpqtuvxz",
|
|
"wl", "jqvxz",
|
|
"wm", "dghjlnqtvwxz",
|
|
"wp", "dfgjkpqtvwxz",
|
|
"wq", "abcdefghijklmnopqrstvwxyz",
|
|
"wr", "cfghjlmpqwx",
|
|
"wt", "bdgjlmnpqtvx",
|
|
"wu", "aikoquvwy",
|
|
"wv", "bcdfghjklmnpqrtuvwxyz",
|
|
"ww", "bcdgkpqstuvxyz",
|
|
"wx", "abcdefghijklmnopqrstuvwxz",
|
|
"wy", "jquwxy",
|
|
"wz", "bcdfghjkmnopqrstuvwxz",
|
|
"xa", "ajoqy",
|
|
"xb", "bcdfghjkmnpqsvwxz",
|
|
"xc", "bcdgjkmnqsvwxz",
|
|
"xd", "bcdfghjklnpqstuvwxyz",
|
|
"xf", "bcdfghjkmnpqtvwxyz",
|
|
"xg", "bcdfghjkmnpqstvwxyz",
|
|
"xh", "cdfghjkmnpqrstvwxz",
|
|
"xi", "jkqy",
|
|
"xj", "abcdefghijklmnopqrstvwxyz",
|
|
"xk", "abcdfghjkmnopqrstuvwxyz",
|
|
"xl", "bcdfghjklmnpqrvwxz",
|
|
"xm", "bcdfghjknpqvwxz",
|
|
"xn", "bcdfghjklmnpqrvwxyz",
|
|
"xp", "bcfjknpqvxz",
|
|
"xq", "abcdefghijklmnopqrstvwxyz",
|
|
"xr", "bcdfghjklnpqrsvwyz",
|
|
"xs", "bdfgjmnqrsvxz",
|
|
"xt", "jkpqvwxz",
|
|
"xu", "fhjkquwx",
|
|
"xv", "bcdefghjklmnpqrsuvwxyz",
|
|
"xw", "bcdfghjklmnpqrtuvwxyz",
|
|
"xx", "bcdefghjkmnpqrstuwyz",
|
|
"xy", "jxy",
|
|
"xz", "abcdefghjklmnpqrstuvwxyz",
|
|
"yb", "cfghjmpqtvwxz",
|
|
"yc", "bdfgjmpqsvwx",
|
|
"yd", "chjkpqvwx",
|
|
"yf", "bcdghjmnpqsvwx",
|
|
"yg", "cfjkpqtxz",
|
|
"yh", "bcdfghjkpqx",
|
|
"yi", "hjqwxy",
|
|
"yj", "bcdfghjklmnpqrstvwxyz",
|
|
"yk", "bcdfgpqvwxz",
|
|
"ym", "dfgjqvxz",
|
|
"yp", "bcdfgjkmqxz",
|
|
"yq", "abcdefghijklmnopqrstvwxyz",
|
|
"yr", "jqx",
|
|
"yt", "bcfgjnpqx",
|
|
"yv", "bcdfghjlmnpqstvwxz",
|
|
"yw", "bfgjklmnpqstuvwxz",
|
|
"yx", "bcdfghjknpqrstuvwxz",
|
|
"yy", "bcdfghjklpqrstvwxz",
|
|
"yz", "bcdfjklmnpqtvwx",
|
|
"zb", "dfgjklmnpqstvwxz",
|
|
"zc", "bcdfgjmnpqstvwxy",
|
|
"zd", "bcdfghjklmnpqstvwxy",
|
|
"zf", "bcdfghijkmnopqrstvwxyz",
|
|
"zg", "bcdfgjkmnpqtvwxyz",
|
|
"zh", "bcfghjlpqstvwxz",
|
|
"zj", "abcdfghjklmnpqrstuvwxyz",
|
|
"zk", "bcdfghjklmpqstvwxz",
|
|
"zl", "bcdfghjlnpqrstvwxz",
|
|
"zm", "bdfghjklmpqstvwxyz",
|
|
"zn", "bcdfghjlmnpqrstuvwxz",
|
|
"zp", "bcdfhjklmnpqstvwxz",
|
|
"zq", "abcdefghijklmnopqrstvwxyz",
|
|
"zr", "bcfghjklmnpqrstvwxyz",
|
|
"zs", "bdfgjmnqrsuwxyz",
|
|
"zt", "bcdfgjkmnpqtuvwxz",
|
|
"zu", "ajqx",
|
|
"zv", "bcdfghjklmnpqrstuvwxyz",
|
|
"zw", "bcdfghjklmnpqrstuvwxyz",
|
|
"zx", "abcdefghijklmnopqrstuvwxyz",
|
|
"zy", "fxy",
|
|
"zz", "cdfhjnpqrvx",
|
|
NULL, NULL
|
|
};
|
|
|
|
/* Used for parsed triples: */
|
|
#define TRIPLES_REST_SIZE 32
|
|
typedef struct Triples Triples;
|
|
struct Triples {
|
|
Triples *next;
|
|
char two[3];
|
|
char rest[TRIPLES_REST_SIZE];
|
|
};
|
|
|
|
Triples *triples = NULL;
|
|
|
|
struct {
|
|
int threshold;
|
|
int ban_action;
|
|
int ban_reason;
|
|
int ban_time;
|
|
} req;
|
|
|
|
struct {
|
|
int threshold;
|
|
BanAction *ban_action;
|
|
char *ban_reason;
|
|
long ban_time;
|
|
int convert_to_lowercase;
|
|
int show_failedconnects;
|
|
SecurityGroup *except;
|
|
} cfg;
|
|
|
|
/* Forward declarations */
|
|
static int init_stuff(void);
|
|
static int init_triples(void);
|
|
static void free_stuff(void);
|
|
static void free_config(void);
|
|
int antirandom_config_test(ConfigFile *, ConfigEntry *, int, int *);
|
|
int antirandom_config_run(ConfigFile *, ConfigEntry *, int);
|
|
int antirandom_config_posttest(int *);
|
|
int antirandom_preconnect(Client *client);
|
|
static int is_exempt(Client *client);
|
|
|
|
MOD_TEST()
|
|
{
|
|
memset(&req, 0, sizeof(req));
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, antirandom_config_test);
|
|
HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, antirandom_config_posttest);
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_INIT()
|
|
{
|
|
MARK_AS_OFFICIAL_MODULE(modinfo);
|
|
if (!init_stuff())
|
|
{
|
|
config_error("antirandom: loading aborted");
|
|
free_stuff();
|
|
return MOD_FAILED;
|
|
}
|
|
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, antirandom_preconnect);
|
|
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, antirandom_config_run);
|
|
|
|
/* Some default values: */
|
|
cfg.convert_to_lowercase = 1;
|
|
cfg.except = safe_alloc(sizeof(SecurityGroup));
|
|
cfg.except->webirc = 1;
|
|
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_LOAD()
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_UNLOAD()
|
|
{
|
|
free_stuff();
|
|
free_config();
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
static void free_config(void)
|
|
{
|
|
safe_free(cfg.ban_reason);
|
|
free_security_group(cfg.except);
|
|
safe_free_all_ban_actions(cfg.ban_action);
|
|
memset(&cfg, 0, sizeof(cfg)); /* needed! */
|
|
}
|
|
|
|
int antirandom_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
|
{
|
|
int errors = 0;
|
|
ConfigEntry *cep;
|
|
|
|
if (type != CONFIG_SET)
|
|
return 0;
|
|
|
|
/* We are only interrested in set::antirandom... */
|
|
if (!ce || !ce->name || strcmp(ce->name, "antirandom"))
|
|
return 0;
|
|
|
|
for (cep = ce->items; cep; cep = cep->next)
|
|
{
|
|
if (!strcmp(cep->name, "except"))
|
|
{
|
|
test_match_block(cf, cep, &errors);
|
|
} else
|
|
if (!strcmp(cep->name, "except-hosts"))
|
|
{
|
|
} else
|
|
if (!strcmp(cep->name, "except-webirc"))
|
|
{
|
|
/* This should normally be UNDER the generic 'set::antirandom::%s with no value'
|
|
* stuff but I put it here because people may think it's a hostlist and then
|
|
* the error can be a tad confusing. -- Syzop
|
|
*/
|
|
if (!cep->value)
|
|
{
|
|
config_error("%s:%i: set::antirandom::except-webirc should be 'yes' or 'no'",
|
|
cep->file->filename, cep->line_number);
|
|
errors++;
|
|
}
|
|
} else
|
|
if (!cep->value)
|
|
{
|
|
config_error("%s:%i: set::antirandom::%s with no value",
|
|
cep->file->filename, cep->line_number, cep->name);
|
|
errors++;
|
|
} else
|
|
if (!strcmp(cep->name, "threshold"))
|
|
{
|
|
req.threshold = 1;
|
|
} else
|
|
if (!strcmp(cep->name, "ban-action") || !strcmp(cep->name, "action"))
|
|
{
|
|
req.ban_action = 1;
|
|
errors += test_ban_action_config(cep);
|
|
} else
|
|
if (!strcmp(cep->name, "ban-reason"))
|
|
{
|
|
req.ban_reason = 1;
|
|
} else
|
|
if (!strcmp(cep->name, "ban-time"))
|
|
{
|
|
req.ban_time = 1;
|
|
} else
|
|
if (!strcmp(cep->name, "convert-to-lowercase"))
|
|
{
|
|
} else
|
|
if (!strcmp(cep->name, "show-failedconnects"))
|
|
{
|
|
} else
|
|
{
|
|
config_error("%s:%i: unknown directive set::antirandom::%s",
|
|
cep->file->filename, cep->line_number, cep->name);
|
|
errors++;
|
|
}
|
|
}
|
|
*errs = errors;
|
|
return errors ? -1 : 1;
|
|
}
|
|
|
|
int antirandom_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
|
|
{
|
|
ConfigEntry *cep, *cep2;
|
|
|
|
if (type != CONFIG_SET)
|
|
return 0;
|
|
|
|
/* We are only interrested in set::antirandom... */
|
|
if (!ce || !ce->name || strcmp(ce->name, "antirandom"))
|
|
return 0;
|
|
|
|
for (cep = ce->items; cep; cep = cep->next)
|
|
{
|
|
if (!strcmp(cep->name, "except"))
|
|
{
|
|
conf_match_block(cf, cep, &cfg.except);
|
|
} else
|
|
if (!strcmp(cep->name, "except-hosts"))
|
|
{
|
|
/* backwards compatible with set::antirandom::except */
|
|
for (cep2 = cep->items; cep2; cep2 = cep2->next)
|
|
unreal_add_masks(&cfg.except->mask, cep2);
|
|
} else
|
|
if (!strcmp(cep->name, "except-webirc"))
|
|
{
|
|
/* backwards compatible with set::antirandom::except */
|
|
cfg.except->webirc = config_checkval(cep->value, CFG_YESNO);
|
|
} else
|
|
if (!strcmp(cep->name, "threshold"))
|
|
{
|
|
cfg.threshold = atoi(cep->value);
|
|
} else
|
|
if (!strcmp(cep->name, "ban-action") || !strcmp(cep->name, "action"))
|
|
{
|
|
parse_ban_action_config(cep, &cfg.ban_action);
|
|
} else
|
|
if (!strcmp(cep->name, "ban-reason"))
|
|
{
|
|
safe_strdup(cfg.ban_reason, cep->value);
|
|
} else
|
|
if (!strcmp(cep->name, "ban-time"))
|
|
{
|
|
cfg.ban_time = config_checkval(cep->value, CFG_TIME);
|
|
} else
|
|
if (!strcmp(cep->name, "convert-to-lowercase"))
|
|
{
|
|
cfg.convert_to_lowercase = config_checkval(cep->value, CFG_YESNO);
|
|
}
|
|
if (!strcmp(cep->name, "show-failedconnects"))
|
|
{
|
|
cfg.show_failedconnects = config_checkval(cep->value, CFG_YESNO);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int antirandom_config_posttest(int *errs)
|
|
{
|
|
int errors = 0;
|
|
|
|
if (!req.threshold) { config_error("set::antirandom::threshold missing"); errors++; }
|
|
if (!req.ban_action) { config_error("set::antirandom::ban-action missing"); errors++; }
|
|
if (!req.ban_time) { config_error("set::antirandom::ban-time missing"); errors++; }
|
|
if (!req.ban_reason) { config_error("set::antirandom::ban-reason missing"); errors++; }
|
|
|
|
*errs = errors;
|
|
return errors ? -1 : 1;
|
|
}
|
|
|
|
static int init_stuff(void)
|
|
{
|
|
if (!init_triples())
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/** Initializes the triples list. */
|
|
static int init_triples(void)
|
|
{
|
|
char **s;
|
|
Triples *e, *last=NULL;
|
|
int cnt=0;
|
|
|
|
for (s=triples_txt; *s; s++)
|
|
{
|
|
cnt++;
|
|
e = safe_alloc(sizeof(Triples));
|
|
if (strlen(*s) > 2)
|
|
{
|
|
config_error("init_triples: error parsing triples_txt, cnt=%d, item='%s' (length>2)",
|
|
cnt, *s);
|
|
return 0;
|
|
}
|
|
strcpy(e->two, *s); /* (SAFE) */
|
|
s++;
|
|
if (!*s)
|
|
{
|
|
config_error("init_triples: error parsing triples_txt, cnt=%d, got NULL expected param",
|
|
cnt);
|
|
return 0;
|
|
}
|
|
if (strlen(*s) > TRIPLES_REST_SIZE-1)
|
|
{
|
|
config_error("init_triples: error parsing triples_txt, cnt=%d, item='%s' (length>%d)",
|
|
cnt, *s, TRIPLES_REST_SIZE-1);
|
|
return 0;
|
|
}
|
|
strcpy(e->rest, *s); /* (SAFE) */
|
|
|
|
/* Append at end of list (to keep it in order, not importent yet, but..) */
|
|
if (last)
|
|
last->next = e;
|
|
else
|
|
triples = e; /*(head)*/
|
|
last = e;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/** Run the actual tests over this string.
|
|
* There are 3 tests:
|
|
* - weird chars (not used)
|
|
* - sregexes (not used)
|
|
* - triples (three-letter combinations)
|
|
*/
|
|
static int internal_getscore(char *str)
|
|
{
|
|
Triples *t;
|
|
register char *s;
|
|
int score = 0;
|
|
int highest_vowels=0, highest_consonants=0, highest_digits=0;
|
|
int vowels=0, consonants=0, digits=0;
|
|
|
|
/* Fast digit/consonant/vowel checks... */
|
|
for (s=str; *s; s++)
|
|
{
|
|
if ((*s >= '0') && (*s <= '9'))
|
|
digits++;
|
|
else {
|
|
highest_digits = MAX(highest_digits, digits);
|
|
digits = 0;
|
|
}
|
|
if (strchr("bcdfghjklmnpqrstvwxz", *s))
|
|
consonants++;
|
|
else {
|
|
highest_consonants = MAX(highest_consonants, consonants);
|
|
consonants = 0;
|
|
}
|
|
if (strchr("aeiou", *s))
|
|
vowels++;
|
|
else {
|
|
highest_vowels = MAX(highest_vowels, vowels);
|
|
vowels = 0;
|
|
}
|
|
}
|
|
|
|
digits = MAX(highest_digits, digits);
|
|
consonants = MAX(highest_consonants, consonants);
|
|
vowels = MAX(highest_vowels, vowels);
|
|
|
|
if (digits >= 5)
|
|
{
|
|
score += digits;
|
|
}
|
|
if (vowels >= 4)
|
|
{
|
|
score += vowels;
|
|
}
|
|
if (consonants >= 4)
|
|
{
|
|
score += consonants;
|
|
}
|
|
|
|
for (t=triples; t; t=t->next)
|
|
{
|
|
for (s=str; *s; s++)
|
|
if ((t->two[0] == s[0]) && (t->two[1] == s[1]) && s[2] && strchr(t->rest, s[2]))
|
|
{
|
|
score++; /* OK */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return score;
|
|
}
|
|
|
|
/** Returns "spam score".
|
|
* @note a user is expected, do not call for anything else (eg: servers)
|
|
*/
|
|
static int get_spam_score(Client *client)
|
|
{
|
|
char *nick = client->name;
|
|
char *user = client->user->username;
|
|
char *gecos = client->info;
|
|
char nbuf[NICKLEN+1], ubuf[USERLEN+1], rbuf[REALLEN+1];
|
|
int nscore, uscore, gscore, score;
|
|
|
|
if (cfg.convert_to_lowercase)
|
|
{
|
|
strtolower_safe(nbuf, nick, sizeof(nbuf));
|
|
strtolower_safe(ubuf, user, sizeof(ubuf));
|
|
strtolower_safe(rbuf, gecos, sizeof(rbuf));
|
|
nick = nbuf;
|
|
user = ubuf;
|
|
gecos = rbuf;
|
|
}
|
|
|
|
nscore = internal_getscore(nick);
|
|
uscore = internal_getscore(user);
|
|
gscore = internal_getscore(gecos);
|
|
score = nscore + uscore + gscore;
|
|
|
|
return score;
|
|
}
|
|
|
|
int antirandom_preconnect(Client *client)
|
|
{
|
|
int score;
|
|
|
|
if (is_exempt(client))
|
|
return HOOK_CONTINUE;
|
|
|
|
score = get_spam_score(client);
|
|
if (score > cfg.threshold)
|
|
{
|
|
int n = take_action(client, cfg.ban_action, cfg.ban_reason, cfg.ban_time, 0, NULL);
|
|
if ((n == BAN_ACT_WARN) || (n == BAN_ACT_SOFT_WARN))
|
|
{
|
|
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
|
"[antirandom] would have denied access to user with score $score: $client.details:$client.user.realname",
|
|
log_data_integer("score", score));
|
|
} else
|
|
if (n <= 0)
|
|
{
|
|
/* No action / exempt */
|
|
} else
|
|
{
|
|
if (cfg.show_failedconnects)
|
|
{
|
|
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
|
"[antirandom] denied access to user with score $score: $client.details:$client.user.realname",
|
|
log_data_integer("score", score));
|
|
}
|
|
return HOOK_DENY;
|
|
}
|
|
}
|
|
return HOOK_CONTINUE;
|
|
}
|
|
|
|
static void free_stuff(void)
|
|
{
|
|
Triples *t, *t_next;
|
|
|
|
for (t=triples; t; t=t_next)
|
|
{
|
|
t_next = t->next;
|
|
safe_free(t);
|
|
}
|
|
triples = NULL;
|
|
}
|
|
|
|
/** Is this user exempt from antirandom interventions? */
|
|
static int is_exempt(Client *client)
|
|
{
|
|
if (user_allowed_by_security_group(client, cfg.except))
|
|
return 1;
|
|
|
|
if (find_tkl_exception(TKL_ANTIRANDOM, client))
|
|
return 1;
|
|
|
|
/* Soft ban and logged in? */
|
|
if (only_soft_actions(cfg.ban_action) && IsLoggedIn(client))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|