unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

antirandom.c (21862B)

      1 /*
      2  * IRC - Internet Relay Chat, antirandom.c
      3  * (C) Copyright 2004-2016, Bram Matthys (Syzop) <syzop@vulnscan.org>
      4  *
      5  * Contains ideas from Keith Dunnett <keith@dunnett.org>
      6  * Most of the detection mechanisms come from SpamAssassin FVGT_Tripwire.
      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 ModuleHeader MOD_HEADER
     26   = {
     27 	"antirandom",
     28 	"1.5",
     29 	"Detect and ban users with random names",
     30 	"UnrealIRCd Team",
     31 	"unrealircd-6",
     32     };
     33 
     34 #ifndef MAX
     35  #define MAX(x,y) ((x) > (y) ? (x) : (y))
     36 #endif
     37 
     38 /* "<char1><char2>" followed by "<rest>" */
     39 static char *triples_txt[] = {
     40 	"aj", "fqtvxz",
     41 	"aq", "deghjkmnprtxyz",
     42 	"av", "bfhjqwxz",
     43 	"az", "jwx",
     44 	"bd", "bghjkmpqvxz",
     45 	"bf", "bcfgjknpqvwxyz",
     46 	"bg", "bdfghjkmnqstvxz",
     47 	"bh", "bfhjkmnqvwxz",
     48 	"bj", "bcdfghjklmpqtvwxyz",
     49 	"bk", "dfjkmqrvwxyz",
     50 	"bl", "bgpqwxz",
     51 	"bm", "bcdflmnqz",
     52 	"bn", "bghjlmnpqtvwx",
     53 	"bp", "bfgjknqvxz",
     54 	"bq", "bcdefghijklmnopqrstvwxyz",
     55 	"bt", "dgjkpqtxz",
     56 	"bv", "bfghjklnpqsuvwxz",
     57 	"bw", "bdfjknpqsuwxyz",
     58 	"bx", "abcdfghijklmnopqtuvwxyz",
     59 	"bz", "bcdfgjklmnpqrstvwxz",
     60 	"cb", "bfghjkpqyz",
     61 	"cc", "gjqxz",
     62 	"cd", "hjkqvwxz",
     63 	"cf", "gjknqvwyz",
     64 	"cg", "bdfgjkpqvz",
     65 	"cl", "fghjmpqxz",
     66 	"cm", "bjkqv",
     67 	"cn", "bghjkpqwxz",
     68 	"cp", "gjkvxyz",
     69 	"cq", "abcdefghijklmnopqsvwxyz",
     70 	"cr", "gjqx",
     71 	"cs", "gjxz",
     72 	"cv", "bdfghjklmnquvwxyz",
     73 	"cx", "abdefghjklmnpqrstuvwxyz",
     74 	"cy", "jqy",
     75 	"cz", "bcdfghjlpqrtvwxz",
     76 	"db", "bdgjnpqtxz",
     77 	"dc", "gjqxz",
     78 	"dd", "gqz",
     79 	"df", "bghjknpqvxyz",
     80 	"dg", "bfgjqvxz",
     81 	"dh", "bfkmnqwxz",
     82 	"dj", "bdfghjklnpqrwxz",
     83 	"dk", "cdhjkpqrtuvwxz",
     84 	"dl", "bfhjknqwxz",
     85 	"dm", "bfjnqw",
     86 	"dn", "fgjkmnpqvwz",
     87 	"dp", "bgjkqvxz",
     88 	"dq", "abcefghijkmnopqtvwxyz",
     89 	"dr", "bfkqtvx",
     90 	"dt", "qtxz",
     91 	"dv", "bfghjknqruvwyz",
     92 	"dw", "cdfjkmnpqsvwxz",
     93 	"dx", "abcdeghjklmnopqrsuvwxyz",
     94 	"dy", "jyz",
     95 	"dz", "bcdfgjlnpqrstvxz",
     96 	"eb", "jqx",
     97 	"eg", "cjvxz",
     98 	"eh", "hxz",
     99 	"ej", "fghjpqtwxyz",
    100 	"ek", "jqxz",
    101 	"ep", "jvx",
    102 	"eq", "bcghijkmotvxyz",
    103 	"ev", "bfpq",
    104 	"fc", "bdjkmnqvxz",
    105 	"fd", "bgjklqsvyz",
    106 	"fg", "fgjkmpqtvwxyz",
    107 	"fh", "bcfghjkpqvwxz",
    108 	"fj", "bcdfghijklmnpqrstvwxyz",
    109 	"fk", "bcdfghjkmpqrstvwxz",
    110 	"fl", "fjkpqxz",
    111 	"fm", "dfhjlmvwxyz",
    112 	"fn", "bdfghjklnqrstvwxz",
    113 	"fp", "bfjknqtvwxz",
    114 	"fq", "abcefghijklmnopqrstvwxyz",
    115 	"fr", "nqxz",
    116 	"fs", "gjxz",
    117 	"ft", "jqx",
    118 	"fv", "bcdfhjklmnpqtuvwxyz",
    119 	"fw", "bcfgjklmpqstuvwxyz",
    120 	"fx", "bcdfghjklmnpqrstvwxyz",
    121 	"fy", "ghjpquvxy",
    122 	"fz", "abcdfghjklmnpqrtuvwxyz",
    123 	"gb", "bcdknpqvwx",
    124 	"gc", "gjknpqwxz",
    125 	"gd", "cdfghjklmqtvwxz",
    126 	"gf", "bfghjkmnpqsvwxyz",
    127 	"gg", "jkqvxz",
    128 	"gj", "bcdfghjklmnpqrstvwxyz",
    129 	"gk", "bcdfgjkmpqtvwxyz",
    130 	"gl", "fgjklnpqwxz",
    131 	"gm", "dfjkmnqvxz",
    132 	"gn", "jkqvxz",
    133 	"gp", "bjknpqtwxyz",
    134 	"gq", "abcdefghjklmnopqrsvwxyz",
    135 	"gr", "jkqt",
    136 	"gt", "fjknqvx",
    137 	"gu", "qwx",
    138 	"gv", "bcdfghjklmpqstvwxyz",
    139 	"gw", "bcdfgjknpqtvwxz",
    140 	"gx", "abcdefghjklmnopqrstvwxyz",
    141 	"gy", "jkqxy",
    142 	"gz", "bcdfgjklmnopqrstvxyz",
    143 	"hb", "bcdfghjkqstvwxz",
    144 	"hc", "cjknqvwxz",
    145 	"hd", "fgjnpvz",
    146 	"hf", "bfghjkmnpqtvwxyz",
    147 	"hg", "bcdfgjknpqsxyz",
    148 	"hh", "bcgklmpqrtvwxz",
    149 	"hj", "bcdfgjkmpqtvwxyz",
    150 	"hk", "bcdgkmpqrstvwxz",
    151 	"hl", "jxz",
    152 	"hm", "dhjqrvwxz",
    153 	"hn", "jrxz",
    154 	"hp", "bjkmqvwxyz",
    155 	"hq", "abcdefghijklmnopqrstvwyz",
    156 	"hr", "cjqx",
    157 	"hs", "jqxz",
    158 	"hv", "bcdfgjklmnpqstuvwxz",
    159 	"hw", "bcfgjklnpqsvwxz",
    160 	"hx", "abcdefghijklmnopqrstuvwxyz",
    161 	"hz", "bcdfghjklmnpqrstuvwxz",
    162 	"ib", "jqx",
    163 	"if", "jqvwz",
    164 	"ih", "bgjqx",
    165 	"ii", "bjqxy",
    166 	"ij", "cfgqxy",
    167 	"ik", "bcfqx",
    168 	"iq", "cdefgjkmnopqtvxyz",
    169 	"iu", "hiwxy",
    170 	"iv", "cfgmqx",
    171 	"iw", "dgjkmnpqtvxz",
    172 	"ix", "jkqrxz",
    173 	"iy", "bcdfghjklpqtvwx",
    174 	"jb", "bcdghjklmnopqrtuvwxyz",
    175 	"jc", "cfgjkmnopqvwxy",
    176 	"jd", "cdfghjlmnpqrtvwx",
    177 	"jf", "abcdfghjlnopqrtuvwxyz",
    178 	"jg", "bcdfghijklmnopqstuvwxyz",
    179 	"jh", "bcdfghjklmnpqrxyz",
    180 	"jj", "bcdfghjklmnopqrstuvwxyz",
    181 	"jk", "bcdfghjknqrtwxyz",
    182 	"jl", "bcfghjmnpqrstuvwxyz",
    183 	"jm", "bcdfghiklmnqrtuvwyz",
    184 	"jn", "bcfjlmnpqsuvwxz",
    185 	"jp", "bcdfhijkmpqstvwxyz",
    186 	"jq", "abcdefghijklmnopqrstuvwxyz",
    187 	"jr", "bdfhjklpqrstuvwxyz",
    188 	"js", "bfgjmoqvxyz",
    189 	"jt", "bcdfghjlnpqrtvwxz",
    190 	"jv", "abcdfghijklpqrstvwxyz",
    191 	"jw", "bcdefghijklmpqrstuwxyz",
    192 	"jx", "abcdefghijklmnopqrstuvwxyz",
    193 	"jy", "bcdefghjkpqtuvwxyz",
    194 	"jz", "bcdfghijklmnopqrstuvwxyz",
    195 	"kb", "bcdfghjkmqvwxz",
    196 	"kc", "cdfgjknpqtwxz",
    197 	"kd", "bfghjklmnpqsvwxyz",
    198 	"kf", "bdfghjkmnpqsvwxyz",
    199 	"kg", "cghjkmnqtvwxyz",
    200 	"kh", "cfghjkqx",
    201 	"kj", "bcdfghjkmnpqrstwxyz",
    202 	"kk", "bcdfgjmpqswxz",
    203 	"kl", "cfghlmqstwxz",
    204 	"km", "bdfghjknqrstwxyz",
    205 	"kn", "bcdfhjklmnqsvwxz",
    206 	"kp", "bdfgjkmpqvxyz",
    207 	"kq", "abdefghijklmnopqrstvwxyz",
    208 	"kr", "bcdfghjmqrvwx",
    209 	"ks", "jqx",
    210 	"kt", "cdfjklqvx",
    211 	"ku", "qux",
    212 	"kv", "bcfghjklnpqrstvxyz",
    213 	"kw", "bcdfgjklmnpqsvwxz",
    214 	"kx", "abcdefghjklmnopqrstuvwxyz",
    215 	"ky", "vxy",
    216 	"kz", "bcdefghjklmnpqrstuvwxyz",
    217 	"lb", "cdgkqtvxz",
    218 	"lc", "bqx",
    219 	"lg", "cdfgpqvxz",
    220 	"lh", "cfghkmnpqrtvx",
    221 	"lk", "qxz",
    222 	"ln", "cfjqxz",
    223 	"lp", "jkqxz",
    224 	"lq", "bcdefhijklmopqrstvwxyz",
    225 	"lr", "dfgjklmpqrtvwx",
    226 	"lv", "bcfhjklmpwxz",
    227 	"lw", "bcdfgjknqxz",
    228 	"lx", "bcdfghjklmnpqrtuwz",
    229 	"lz", "cdjptvxz",
    230 	"mb", "qxz",
    231 	"md", "hjkpvz",
    232 	"mf", "fkpqvwxz",
    233 	"mg", "cfgjnpqsvwxz",
    234 	"mh", "bchjkmnqvx",
    235 	"mj", "bcdfghjknpqrstvwxyz",
    236 	"mk", "bcfgklmnpqrvwxz",
    237 	"ml", "jkqz",
    238 	"mm", "qvz",
    239 	"mn", "fhjkqxz",
    240 	"mq", "bdefhjklmnopqtwxyz",
    241 	"mr", "jklqvwz",
    242 	"mt", "jkq",
    243 	"mv", "bcfghjklmnqtvwxz",
    244 	"mw", "bcdfgjklnpqsuvwxyz",
    245 	"mx", "abcefghijklmnopqrstvwxyz",
    246 	"mz", "bcdfghjkmnpqrstvwxz",
    247 	"nb", "hkmnqxz",
    248 	"nf", "bghqvxz",
    249 	"nh", "fhjkmqtvxz",
    250 	"nk", "qxz",
    251 	"nl", "bghjknqvwxz",
    252 	"nm", "dfghjkqtvwxz",
    253 	"np", "bdjmqwxz",
    254 	"nq", "abcdfghjklmnopqrtvwxyz",
    255 	"nr", "bfjkqstvx",
    256 	"nv", "bcdfgjkmnqswxz",
    257 	"nw", "dgjpqvxz",
    258 	"nx", "abfghjknopuyz",
    259 	"nz", "cfqrxz",
    260 	"oc", "fjvw",
    261 	"og", "qxz",
    262 	"oh", "fqxz",
    263 	"oj", "bfhjmqrswxyz",
    264 	"ok", "qxz",
    265 	"oq", "bcdefghijklmnopqrstvwxyz",
    266 	"ov", "bfhjqwx",
    267 	"oy", "qxy",
    268 	"oz", "fjpqtvx",
    269 	"pb", "fghjknpqvwz",
    270 	"pc", "gjq",
    271 	"pd", "bgjkvwxz",
    272 	"pf", "hjkmqtvwyz",
    273 	"pg", "bdfghjkmqsvwxyz",
    274 	"ph", "kqvx",
    275 	"pk", "bcdfhjklmpqrvx",
    276 	"pl", "ghkqvwx",
    277 	"pm", "bfhjlmnqvwyz",
    278 	"pn", "fjklmnqrtvwz",
    279 	"pp", "gqwxz",
    280 	"pq", "abcdefghijklmnopqstvwxyz",
    281 	"pr", "hjkqrwx",
    282 	"pt", "jqxz",
    283 	"pv", "bdfghjklquvwxyz",
    284 	"pw", "fjkmnpqsuvwxz",
    285 	"px", "abcdefghijklmnopqrstuvwxyz",
    286 	"pz", "bdefghjklmnpqrstuvwxyz",
    287 	"qa", "ceghkopqxy",
    288 	"qb", "bcdfghjklmnqrstuvwxyz",
    289 	"qc", "abcdfghijklmnopqrstuvwxyz",
    290 	"qd", "defghijklmpqrstuvwxyz",
    291 	"qe", "abceghjkmopquwxyz",
    292 	"qf", "abdfghijklmnopqrstuvwxyz",
    293 	"qg", "abcdefghijklmnopqrtuvwxz",
    294 	"qh", "abcdefghijklmnopqrstuvwxyz",
    295 	"qi", "efgijkmpwx",
    296 	"qj", "abcdefghijklmnopqrstuvwxyz",
    297 	"qk", "abcdfghijklmnopqrsuvwxyz",
    298 	"ql", "abcefghjklmnopqrtuvwxyz",
    299 	"qm", "bdehijklmnoqrtuvxyz",
    300 	"qn", "bcdefghijklmnoqrtuvwxyz",
    301 	"qo", "abcdefgijkloqstuvwxyz",
    302 	"qp", "abcdefghijkmnopqrsuvwxyz",
    303 	"qq", "bcdefghijklmnopstwxyz",
    304 	"qr", "bdefghijklmnoqruvwxyz",
    305 	"qs", "bcdefgijknqruvwxz",
    306 	"qt", "befghjklmnpqtuvwxz",
    307 	"qu", "cfgjkpwz",
    308 	"qv", "abdefghjklmnopqrtuvwxyz",
    309 	"qw", "bcdfghijkmnopqrstuvwxyz",
    310 	"qx", "abcdefghijklmnopqrstuvwxyz",
    311 	"qy", "abcdefghjklmnopqrstuvwxyz",
    312 	"qz", "abcdefghijklmnopqrstuvwxyz",
    313 	"rb", "fxz",
    314 	"rg", "jvxz",
    315 	"rh", "hjkqrxz",
    316 	"rj", "bdfghjklmpqrstvwxz",
    317 	"rk", "qxz",
    318 	"rl", "jnq",
    319 	"rp", "jxz",
    320 	"rq", "bcdefghijklmnopqrtvwxy",
    321 	"rr", "jpqxz",
    322 	"rv", "bcdfghjmpqrvwxz",
    323 	"rw", "bfgjklqsvxz",
    324 	"rx", "bcdfgjkmnopqrtuvwxz",
    325 	"rz", "djpqvxz",
    326 	"sb", "kpqtvxz",
    327 	"sd", "jqxz",
    328 	"sf", "bghjkpqw",
    329 	"sg", "cgjkqvwxz",
    330 	"sj", "bfghjkmnpqrstvwxz",
    331 	"sk", "qxz",
    332 	"sl", "gjkqwxz",
    333 	"sm", "fkqwxz",
    334 	"sn", "dhjknqvwxz",
    335 	"sq", "bfghjkmopstvwxz",
    336 	"sr", "jklqrwxz",
    337 	"sv", "bfhjklmnqtwxyz",
    338 	"sw", "jkpqvwxz",
    339 	"sx", "bcdefghjklmnopqrtuvwxyz",
    340 	"sy", "qxy",
    341 	"sz", "bdfgjpqsvxz",
    342 	"tb", "cghjkmnpqtvwx",
    343 	"tc", "jnqvx",
    344 	"td", "bfgjkpqtvxz",
    345 	"tf", "ghjkqvwyz",
    346 	"tg", "bdfghjkmpqsx",
    347 	"tj", "bdfhjklmnpqstvwxyz",
    348 	"tk", "bcdfghjklmpqvwxz",
    349 	"tl", "jkqwxz",
    350 	"tm", "bknqtwxz",
    351 	"tn", "fhjkmqvwxz",
    352 	"tp", "bjpqvwxz",
    353 	"tq", "abdefhijklmnopqrstvwxyz",
    354 	"tr", "gjqvx",
    355 	"tv", "bcfghjknpquvwxz",
    356 	"tw", "bcdfjknqvz",
    357 	"tx", "bcdefghjklmnopqrsuvwxz",
    358 	"tz", "jqxz",
    359 	"uc", "fjmvx",
    360 	"uf", "jpqvx",
    361 	"ug", "qvx",
    362 	"uh", "bcgjkpvxz",
    363 	"uj", "wbfghklmqvwx",
    364 	"uk", "fgqxz",
    365 	"uq", "bcdfghijklmnopqrtwxyz",
    366 	"uu", "fijkqvwyz",
    367 	"uv", "bcdfghjkmpqtwxz",
    368 	"uw", "dgjnquvxyz",
    369 	"ux", "jqxz",
    370 	"uy", "jqxyz",
    371 	"uz", "fgkpqrx",
    372 	"vb", "bcdfhijklmpqrtuvxyz",
    373 	"vc", "bgjklnpqtvwxyz",
    374 	"vd", "bdghjklnqvwxyz",
    375 	"vf", "bfghijklmnpqtuvxz",
    376 	"vg", "bcdgjkmnpqtuvwxyz",
    377 	"vh", "bcghijklmnpqrtuvwxyz",
    378 	"vj", "abcdfghijklmnpqrstuvwxyz",
    379 	"vk", "bcdefgjklmnpqruvwxyz",
    380 	"vl", "hjkmpqrvwxz",
    381 	"vm", "bfghjknpquvxyz",
    382 	"vn", "bdhjkmnpqrtuvwxz",
    383 	"vp", "bcdeghjkmopqtuvwyz",
    384 	"vq", "abcdefghijklmnopqrstvwxyz",
    385 	"vr", "fghjknqrtvwxz",
    386 	"vs", "dfgjmqz",
    387 	"vt", "bdfgjklmnqtx",
    388 	"vu", "afhjquwxy",
    389 	"vv", "cdfghjkmnpqrtuwxz",
    390 	"vw", "abcdefghijklmnopqrtuvwxyz",
    391 	"vx", "abcefghjklmnopqrstuvxyz",
    392 	"vy", "oqx",
    393 	"vz", "abcdefgjklmpqrstvwxyz",
    394 	"wb", "bdfghjpqtvxz",
    395 	"wc", "bdfgjkmnqvwx",
    396 	"wd", "dfjpqvxz",
    397 	"wf", "cdghjkmqvwxyz",
    398 	"wg", "bcdfgjknpqtvwxyz",
    399 	"wh", "cdghjklpqvwxz",
    400 	"wj", "bfghijklmnpqrstvwxyz",
    401 	"wk", "cdfgjkpqtuvxz",
    402 	"wl", "jqvxz",
    403 	"wm", "dghjlnqtvwxz",
    404 	"wp", "dfgjkpqtvwxz",
    405 	"wq", "abcdefghijklmnopqrstvwxyz",
    406 	"wr", "cfghjlmpqwx",
    407 	"wt", "bdgjlmnpqtvx",
    408 	"wu", "aikoquvwy",
    409 	"wv", "bcdfghjklmnpqrtuvwxyz",
    410 	"ww", "bcdgkpqstuvxyz",
    411 	"wx", "abcdefghijklmnopqrstuvwxz",
    412 	"wy", "jquwxy",
    413 	"wz", "bcdfghjkmnopqrstuvwxz",
    414 	"xa", "ajoqy",
    415 	"xb", "bcdfghjkmnpqsvwxz",
    416 	"xc", "bcdgjkmnqsvwxz",
    417 	"xd", "bcdfghjklnpqstuvwxyz",
    418 	"xf", "bcdfghjkmnpqtvwxyz",
    419 	"xg", "bcdfghjkmnpqstvwxyz",
    420 	"xh", "cdfghjkmnpqrstvwxz",
    421 	"xi", "jkqy",
    422 	"xj", "abcdefghijklmnopqrstvwxyz",
    423 	"xk", "abcdfghjkmnopqrstuvwxyz",
    424 	"xl", "bcdfghjklmnpqrvwxz",
    425 	"xm", "bcdfghjknpqvwxz",
    426 	"xn", "bcdfghjklmnpqrvwxyz",
    427 	"xp", "bcfjknpqvxz",
    428 	"xq", "abcdefghijklmnopqrstvwxyz",
    429 	"xr", "bcdfghjklnpqrsvwyz",
    430 	"xs", "bdfgjmnqrsvxz",
    431 	"xt", "jkpqvwxz",
    432 	"xu", "fhjkquwx",
    433 	"xv", "bcdefghjklmnpqrsuvwxyz",
    434 	"xw", "bcdfghjklmnpqrtuvwxyz",
    435 	"xx", "bcdefghjkmnpqrstuwyz",
    436 	"xy", "jxy",
    437 	"xz", "abcdefghjklmnpqrstuvwxyz",
    438 	"yb", "cfghjmpqtvwxz",
    439 	"yc", "bdfgjmpqsvwx",
    440 	"yd", "chjkpqvwx",
    441 	"yf", "bcdghjmnpqsvwx",
    442 	"yg", "cfjkpqtxz",
    443 	"yh", "bcdfghjkpqx",
    444 	"yi", "hjqwxy",
    445 	"yj", "bcdfghjklmnpqrstvwxyz",
    446 	"yk", "bcdfgpqvwxz",
    447 	"ym", "dfgjqvxz",
    448 	"yp", "bcdfgjkmqxz",
    449 	"yq", "abcdefghijklmnopqrstvwxyz",
    450 	"yr", "jqx",
    451 	"yt", "bcfgjnpqx",
    452 	"yv", "bcdfghjlmnpqstvwxz",
    453 	"yw", "bfgjklmnpqstuvwxz",
    454 	"yx", "bcdfghjknpqrstuvwxz",
    455 	"yy", "bcdfghjklpqrstvwxz",
    456 	"yz", "bcdfjklmnpqtvwx",
    457 	"zb", "dfgjklmnpqstvwxz",
    458 	"zc", "bcdfgjmnpqstvwxy",
    459 	"zd", "bcdfghjklmnpqstvwxy",
    460 	"zf", "bcdfghijkmnopqrstvwxyz",
    461 	"zg", "bcdfgjkmnpqtvwxyz",
    462 	"zh", "bcfghjlpqstvwxz",
    463 	"zj", "abcdfghjklmnpqrstuvwxyz",
    464 	"zk", "bcdfghjklmpqstvwxz",
    465 	"zl", "bcdfghjlnpqrstvwxz",
    466 	"zm", "bdfghjklmpqstvwxyz",
    467 	"zn", "bcdfghjlmnpqrstuvwxz",
    468 	"zp", "bcdfhjklmnpqstvwxz",
    469 	"zq", "abcdefghijklmnopqrstvwxyz",
    470 	"zr", "bcfghjklmnpqrstvwxyz",
    471 	"zs", "bdfgjmnqrsuwxyz",
    472 	"zt", "bcdfgjkmnpqtuvwxz",
    473 	"zu", "ajqx",
    474 	"zv", "bcdfghjklmnpqrstuvwxyz",
    475 	"zw", "bcdfghjklmnpqrstuvwxyz",
    476 	"zx", "abcdefghijklmnopqrstuvwxyz",
    477 	"zy", "fxy",
    478 	"zz", "cdfhjnpqrvx",
    479 	NULL, NULL
    480 };
    481 
    482 /* Used for parsed triples: */
    483 #define TRIPLES_REST_SIZE	32
    484 typedef struct Triples Triples;
    485 struct Triples {
    486 	Triples *next;
    487 	char two[3];
    488 	char rest[TRIPLES_REST_SIZE];
    489 };
    490 
    491 Triples *triples = NULL;
    492 
    493 struct {
    494 	int threshold;
    495 	int ban_action;
    496 	int ban_reason;
    497 	int ban_time;
    498 } req;
    499 
    500 struct {
    501 	int threshold;
    502 	BanAction ban_action;
    503 	char *ban_reason;
    504 	long ban_time;
    505 	int convert_to_lowercase;
    506 	int show_failedconnects;
    507 	SecurityGroup *except;
    508 } cfg;
    509 
    510 /* Forward declarations */
    511 static int init_stuff(void);
    512 static int init_triples(void);
    513 static void free_stuff(void);
    514 static void free_config(void);
    515 int antirandom_config_test(ConfigFile *, ConfigEntry *, int, int *);
    516 int antirandom_config_run(ConfigFile *, ConfigEntry *, int);
    517 int antirandom_config_posttest(int *);
    518 int antirandom_preconnect(Client *client);
    519 static int is_exempt(Client *client);
    520 
    521 MOD_TEST()
    522 {
    523 	memset(&req, 0, sizeof(req));
    524 	memset(&cfg, 0, sizeof(cfg));
    525 	HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, antirandom_config_test);
    526 	HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, antirandom_config_posttest);
    527 	return MOD_SUCCESS;
    528 }
    529 
    530 MOD_INIT()
    531 {
    532 	MARK_AS_OFFICIAL_MODULE(modinfo);
    533 	if (!init_stuff())
    534 	{
    535 		config_error("antirandom: loading aborted");
    536 		free_stuff();
    537 		return MOD_FAILED;
    538 	}
    539 	HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, antirandom_preconnect);
    540 	HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, antirandom_config_run);
    541 
    542 	/* Some default values: */
    543 	cfg.convert_to_lowercase = 1;
    544 	cfg.except = safe_alloc(sizeof(SecurityGroup));
    545 	cfg.except->webirc = 1;
    546 
    547 	return MOD_SUCCESS;
    548 }
    549 
    550 MOD_LOAD()
    551 {
    552 	return MOD_SUCCESS;
    553 }
    554 
    555 MOD_UNLOAD()
    556 {
    557 	free_stuff();
    558 	free_config();
    559 	return MOD_SUCCESS;
    560 }
    561 
    562 static void free_config(void)
    563 {
    564 	safe_free(cfg.ban_reason);
    565 	free_security_group(cfg.except);
    566 	memset(&cfg, 0, sizeof(cfg)); /* needed! */
    567 }
    568 
    569 int antirandom_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
    570 {
    571 	int errors = 0;
    572 	ConfigEntry *cep;
    573 
    574 	if (type != CONFIG_SET)
    575 		return 0;
    576 	
    577 	/* We are only interrested in set::antirandom... */
    578 	if (!ce || !ce->name || strcmp(ce->name, "antirandom"))
    579 		return 0;
    580 	
    581 	for (cep = ce->items; cep; cep = cep->next)
    582 	{
    583 		if (!strcmp(cep->name, "except"))
    584 		{
    585 			test_match_block(cf, cep, &errors);
    586 		} else
    587 		if (!strcmp(cep->name, "except-hosts"))
    588 		{
    589 		} else
    590 		if (!strcmp(cep->name, "except-webirc"))
    591 		{
    592 			/* This should normally be UNDER the generic 'set::antirandom::%s with no value'
    593 			 * stuff but I put it here because people may think it's a hostlist and then
    594 			 * the error can be a tad confusing. -- Syzop
    595 			 */
    596 			if (!cep->value)
    597 			{
    598 				config_error("%s:%i: set::antirandom::except-webirc should be 'yes' or 'no'",
    599 				             cep->file->filename, cep->line_number);
    600 				errors++;
    601 			}
    602 		} else
    603 		if (!cep->value)
    604 		{
    605 			config_error("%s:%i: set::antirandom::%s with no value",
    606 				cep->file->filename, cep->line_number, cep->name);
    607 			errors++;
    608 		} else
    609 		if (!strcmp(cep->name, "threshold"))
    610 		{
    611 			req.threshold = 1;
    612 		} else
    613 		if (!strcmp(cep->name, "ban-action"))
    614 		{
    615 			if (!banact_stringtoval(cep->value))
    616 			{
    617 				config_error("%s:%i: set::antirandom::ban-action: unknown action '%s'",
    618 					cep->file->filename, cep->line_number, cep->value);
    619 				errors++;
    620 			} else
    621 				req.ban_action = 1;
    622 		} else
    623 		if (!strcmp(cep->name, "ban-reason"))
    624 		{
    625 			req.ban_reason = 1;
    626 		} else
    627 		if (!strcmp(cep->name, "ban-time"))
    628 		{
    629 			req.ban_time = 1;
    630 		} else
    631 		if (!strcmp(cep->name, "convert-to-lowercase"))
    632 		{
    633 		} else
    634 		if (!strcmp(cep->name, "show-failedconnects"))
    635 		{
    636 		} else
    637 		{
    638 			config_error("%s:%i: unknown directive set::antirandom::%s",
    639 				cep->file->filename, cep->line_number, cep->name);
    640 			errors++;
    641 		}
    642 	}
    643 	*errs = errors;
    644 	return errors ? -1 : 1;
    645 }
    646 
    647 int antirandom_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
    648 {
    649 	ConfigEntry *cep, *cep2;
    650 
    651 	if (type != CONFIG_SET)
    652 		return 0;
    653 	
    654 	/* We are only interrested in set::antirandom... */
    655 	if (!ce || !ce->name || strcmp(ce->name, "antirandom"))
    656 		return 0;
    657 	
    658 	for (cep = ce->items; cep; cep = cep->next)
    659 	{
    660 		if (!strcmp(cep->name, "except"))
    661 		{
    662 			conf_match_block(cf, cep, &cfg.except);
    663 		} else
    664 		if (!strcmp(cep->name, "except-hosts"))
    665 		{
    666 			/* backwards compatible with set::antirandom::except */
    667 			for (cep2 = cep->items; cep2; cep2 = cep2->next)
    668 				unreal_add_masks(&cfg.except->mask, cep2);
    669 		} else
    670 		if (!strcmp(cep->name, "except-webirc"))
    671 		{
    672 			/* backwards compatible with set::antirandom::except */
    673 			cfg.except->webirc = config_checkval(cep->value, CFG_YESNO);
    674 		} else
    675 		if (!strcmp(cep->name, "threshold"))
    676 		{
    677 			cfg.threshold = atoi(cep->value);
    678 		} else
    679 		if (!strcmp(cep->name, "ban-action"))
    680 		{
    681 			cfg.ban_action = banact_stringtoval(cep->value);
    682 		} else
    683 		if (!strcmp(cep->name, "ban-reason"))
    684 		{
    685 			safe_strdup(cfg.ban_reason, cep->value);
    686 		} else
    687 		if (!strcmp(cep->name, "ban-time"))
    688 		{
    689 			cfg.ban_time = config_checkval(cep->value, CFG_TIME);
    690 		} else
    691 		if (!strcmp(cep->name, "convert-to-lowercase"))
    692 		{
    693 			cfg.convert_to_lowercase = config_checkval(cep->value, CFG_YESNO);
    694 		}
    695 		if (!strcmp(cep->name, "show-failedconnects"))
    696 		{
    697 			cfg.show_failedconnects = config_checkval(cep->value, CFG_YESNO);
    698 		}
    699 	}
    700 	return 1;
    701 }
    702 
    703 int antirandom_config_posttest(int *errs)
    704 {
    705 	int errors = 0;
    706 
    707 	if (!req.threshold) { config_error("set::antirandom::threshold missing"); errors++; }
    708 	if (!req.ban_action) { config_error("set::antirandom::ban-action missing"); errors++; }
    709 	if (!req.ban_time) { config_error("set::antirandom::ban-time missing"); errors++; }
    710 	if (!req.ban_reason) { config_error("set::antirandom::ban-reason missing"); errors++; }
    711 	
    712 	*errs = errors;
    713 	return errors ? -1 : 1;
    714 }
    715 
    716 static int init_stuff(void)
    717 {
    718 	if (!init_triples())
    719 		return 0;
    720 	return 1;
    721 }
    722 
    723 /** Initializes the triples list. */
    724 static int init_triples(void)
    725 {
    726 	char **s;
    727 	Triples *e, *last=NULL;
    728 	int cnt=0;
    729 
    730 	for (s=triples_txt; *s; s++)
    731 	{
    732 		cnt++;
    733 		e = safe_alloc(sizeof(Triples));
    734 		if (strlen(*s) > 2)
    735 		{
    736 			config_error("init_triples: error parsing triples_txt, cnt=%d, item='%s' (length>2)",
    737 				cnt, *s);
    738 			return 0;
    739 		}
    740 		strcpy(e->two, *s); /* (SAFE) */
    741 		s++;
    742 		if (!*s)
    743 		{
    744 			config_error("init_triples: error parsing triples_txt, cnt=%d, got NULL expected param",
    745 				cnt);
    746 			return 0;
    747 		}
    748 		if (strlen(*s) > TRIPLES_REST_SIZE-1)
    749 		{
    750 			config_error("init_triples: error parsing triples_txt, cnt=%d, item='%s' (length>%d)",
    751 				cnt, *s, TRIPLES_REST_SIZE-1);
    752 			return 0;
    753 		}
    754 		strcpy(e->rest, *s); /* (SAFE) */
    755 
    756 		/* Append at end of list (to keep it in order, not importent yet, but..) */
    757 		if (last)
    758 			last->next = e;
    759 		else
    760 			triples = e; /*(head)*/
    761 		last = e;
    762 	}
    763 	return 1;
    764 }
    765 
    766 /** Run the actual tests over this string.
    767  * There are 3 tests:
    768  * - weird chars (not used)
    769  * - sregexes (not used)
    770  * - triples (three-letter combinations)
    771  */
    772 static int internal_getscore(char *str)
    773 {
    774 	Triples *t;
    775 	register char *s;
    776 	int score = 0;
    777 	int highest_vowels=0, highest_consonants=0, highest_digits=0;
    778 	int vowels=0, consonants=0, digits=0;
    779 
    780 	/* Fast digit/consonant/vowel checks... */
    781 	for (s=str; *s; s++)
    782 	{
    783 		if ((*s >= '0') && (*s <= '9'))
    784 			digits++;
    785 		else {
    786 			highest_digits = MAX(highest_digits, digits);
    787 			digits = 0;
    788 		}
    789 		if (strchr("bcdfghjklmnpqrstvwxz", *s))
    790 			consonants++;
    791 		else {
    792 			highest_consonants = MAX(highest_consonants, consonants);
    793 			consonants = 0;
    794 		}
    795 		if (strchr("aeiou", *s))
    796 			vowels++;
    797 		else {
    798 			highest_vowels = MAX(highest_vowels, vowels);
    799 			vowels = 0;
    800 		}
    801 	}
    802 
    803 	digits = MAX(highest_digits, digits);
    804 	consonants = MAX(highest_consonants, consonants);
    805 	vowels = MAX(highest_vowels, vowels);
    806 	
    807 	if (digits >= 5)
    808 	{
    809 		score += digits;
    810 	}
    811 	if (vowels >= 4)
    812 	{
    813 		score += vowels;
    814 	}
    815 	if (consonants >= 4)
    816 	{
    817 		score += consonants;
    818 	}
    819 	
    820 	for (t=triples; t; t=t->next)
    821 	{
    822 		for (s=str; *s; s++)
    823 			if ((t->two[0] == s[0]) && (t->two[1] == s[1]) && s[2] && strchr(t->rest, s[2]))
    824 			{
    825 				score++; /* OK */
    826 			}
    827 	}
    828 
    829 	
    830 	
    831 	return score;
    832 }
    833 
    834 /** Returns "spam score".
    835  * @note a user is expected, do not call for anything else (eg: servers)
    836  */
    837 static int get_spam_score(Client *client)
    838 {
    839 	char *nick = client->name;
    840 	char *user = client->user->username;
    841 	char *gecos = client->info;
    842 	char nbuf[NICKLEN+1], ubuf[USERLEN+1], rbuf[REALLEN+1];
    843 	int nscore, uscore, gscore, score;
    844 
    845 	if (cfg.convert_to_lowercase)
    846 	{
    847 		strtolower_safe(nbuf, nick, sizeof(nbuf));
    848 		strtolower_safe(ubuf, user, sizeof(ubuf));
    849 		strtolower_safe(rbuf, gecos, sizeof(rbuf));
    850 		nick = nbuf;
    851 		user = ubuf;
    852 		gecos = rbuf;
    853 	}
    854 
    855 	nscore = internal_getscore(nick);
    856 	uscore = internal_getscore(user);
    857 	gscore = internal_getscore(gecos);
    858 	score = nscore + uscore + gscore;
    859 
    860 	return score;
    861 }
    862 
    863 int antirandom_preconnect(Client *client)
    864 {
    865 	int score;
    866 
    867 	if (is_exempt(client))
    868 		return HOOK_CONTINUE;
    869 
    870 	score = get_spam_score(client);
    871 	if (score > cfg.threshold)
    872 	{
    873 		if (cfg.ban_action == BAN_ACT_WARN)
    874 		{
    875 			unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
    876 			           "[antirandom] would have denied access to user with score $score: $client.details:$client.user.realname",
    877 			           log_data_integer("score", score));
    878 			return HOOK_CONTINUE;
    879 		}
    880 		if (cfg.show_failedconnects)
    881 		{
    882 			unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
    883 			           "[antirandom] denied access to user with score $score: $client.details:$client.user.realname",
    884 			           log_data_integer("score", score));
    885 		}
    886 		place_host_ban(client, cfg.ban_action, cfg.ban_reason, cfg.ban_time);
    887 		return HOOK_DENY;
    888 	}
    889 	return HOOK_CONTINUE;
    890 }
    891 
    892 static void free_stuff(void)
    893 {
    894 	Triples *t, *t_next;
    895 
    896 	for (t=triples; t; t=t_next)
    897 	{
    898 		t_next = t->next;
    899 		safe_free(t);
    900 	}
    901 	triples = NULL;
    902 }
    903 
    904 /** Is this user exempt from antirandom interventions? */
    905 static int is_exempt(Client *client)
    906 {
    907 	if (user_allowed_by_security_group(client, cfg.except))
    908 		return 1;
    909 
    910 	if (find_tkl_exception(TKL_ANTIRANDOM, client))
    911 		return 1;
    912 
    913 	/* Soft ban and logged in? */
    914 	if (IsSoftBanAction(cfg.ban_action) && IsLoggedIn(client))
    915 		return 1;
    916 
    917 	return 0;
    918 }