]> jfr.im git - solanum.git/blame - extensions/hurt.c
msg: remove last vestiges of the fakelag system. charybdis has never supported fakelag.
[solanum.git] / extensions / hurt.c
CommitLineData
212380e3
AC
1/*
2 * charybdis: an advanced Internet Relay Chat Daemon(ircd).
3 *
4 * Copyright (C) 2006 charybdis development team
5 * All rights reserved
6 *
5366977b 7 * $Id: hurt.c 3161 2007-01-25 07:23:01Z nenolod $
212380e3
AC
8 */
9#include "stdinc.h"
10#include "modules.h"
11#include "hook.h"
12#include "client.h"
13#include "ircd.h"
14#include "send.h"
15#include "numeric.h"
16#include "hostmask.h"
212380e3
AC
17#include "s_conf.h"
18#include "s_newconf.h"
19#include "hash.h"
bd0d352f 20#include "messages.h"
77d3d2db 21#include "s_assert.h"
212380e3
AC
22
23/* {{{ Structures */
24#define HURT_CUTOFF (10) /* protocol messages. */
25#define HURT_DEFAULT_EXPIRE (7 * 24 * 60) /* minutes. */
26#define HURT_EXIT_REASON "Hurt: Failed to identify to services"
27
28enum {
29 HEAL_NICK = 0,
30 HEAL_IP
31};
32
33typedef struct _hurt_state {
34 time_t start_time;
35 uint32_t n_hurts;
ddcb223e 36 rb_dlink_list hurt_clients;
212380e3
AC
37 uint16_t cutoff;
38 time_t default_expire;
39 const char *exit_reason;
40} hurt_state_t;
41
42typedef struct _hurt {
19fcdbd5 43 char *ip;
212380e3
AC
44 struct sockaddr *saddr;
45 int saddr_bits;
19fcdbd5 46 char *reason;
212380e3
AC
47 time_t expire;
48} hurt_t;
49/* }}} */
50
51/* {{{ Prototypes */
760bafda
AC
52static int mo_hurt(struct MsgBuf *msgbuf_p, struct Client *, struct Client *, int, const char **);
53static int me_hurt(struct MsgBuf *msgbuf_p, struct Client *, struct Client *, int, const char **);
54static int mo_heal(struct MsgBuf *msgbuf_p, struct Client *, struct Client *, int, const char **);
55static int me_heal(struct MsgBuf *msgbuf_p, struct Client *, struct Client *, int, const char **);
212380e3
AC
56
57static int modinit(void);
58static void modfini(void);
59
60static void client_exit_hook(hook_data_client_exit *);
61static void new_local_user_hook(struct Client *);
62static void doing_stats_hook(hook_data_int *hdata);
63
64static void hurt_check_event(void *);
65static void hurt_expire_event(void *);
66
67static hurt_t *hurt_new(time_t, const char *, const char *);
68static void hurt_add(hurt_t *);
69static void hurt_propagate(struct Client *, struct Client *, hurt_t *);
70static hurt_t *hurt_find(const char *ip);
71static hurt_t *hurt_find_exact(const char *ip);
72static void hurt_remove(const char *ip);
73static void hurt_destroy(void *hurt);
74
75static int heal_nick(struct Client *, struct Client *);
76
212380e3
AC
77/* }}} */
78
79/* {{{ State containers */
80
ddcb223e 81rb_dlink_list hurt_confs = { NULL, NULL, 0 };
212380e3
AC
82
83/* }}} */
84
85/* {{{ Messages */
86struct Message hurt_msgtab = {
7baa37a9 87 "HURT", 0, 0, 0, 0, {
212380e3
AC
88 mg_ignore, mg_ignore, mg_ignore,
89 mg_ignore, {me_hurt, 0}, {mo_hurt, 3}
90 }
91};
92
93struct Message heal_msgtab = {
7baa37a9 94 "HEAL", 0, 0, 0, 0, {
212380e3
AC
95 mg_ignore, mg_ignore, mg_ignore,
96 mg_ignore, {me_heal, 0}, {mo_heal, 2}
97 }
98};
99/* }}} */
100
101/* {{{ Misc module stuff */
102mapi_hfn_list_av1 hurt_hfnlist[] = {
103 {"client_exit", (hookfn) client_exit_hook},
104 {"new_local_user", (hookfn) new_local_user_hook},
105 {"doing_stats", (hookfn) doing_stats_hook},
106 {NULL, NULL},
107};
108
109mapi_clist_av1 hurt_clist[] = { &hurt_msgtab, &heal_msgtab, NULL };
110
111DECLARE_MODULE_AV1(
112 hurt,
113 modinit,
114 modfini,
115 hurt_clist,
116 NULL,
117 hurt_hfnlist,
5366977b 118 "$Revision: 3161 $"
212380e3
AC
119);
120/* }}} */
121
122hurt_state_t hurt_state = {
123 .cutoff = HURT_CUTOFF,
124 .default_expire = HURT_DEFAULT_EXPIRE,
125 .exit_reason = HURT_EXIT_REASON,
126};
127
128/*
129 * Module constructor/destructor.
130 */
131
132/* {{{ static int modinit() */
036a10a9
AC
133
134struct ev_entry *hurt_expire_ev = NULL;
135struct ev_entry *hurt_check_ev = NULL;
136
212380e3
AC
137static int
138modinit(void)
139{
140 /* set-up hurt_state. */
954012d3 141 hurt_state.start_time = rb_current_time();
212380e3
AC
142
143 /* add our event handlers. */
036a10a9
AC
144 hurt_expire_ev = rb_event_add("hurt_expire", hurt_expire_event, NULL, 60);
145 hurt_check_ev = rb_event_add("hurt_check", hurt_check_event, NULL, 5);
212380e3
AC
146
147 return 0;
148}
149/* }}} */
150
151/* {{{ static void modfini() */
152static void
153modfini(void)
154{
ddcb223e 155 rb_dlink_node *ptr, *next_ptr;
212380e3
AC
156
157 /* and delete our events. */
036a10a9
AC
158 rb_event_delete(hurt_expire_ev);
159 rb_event_delete(hurt_check_ev);
212380e3 160
ddcb223e 161 RB_DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_state.hurt_clients.head)
212380e3 162 {
ddcb223e 163 rb_dlinkDestroy(ptr, &hurt_state.hurt_clients);
212380e3
AC
164 }
165}
166/* }}} */
167
168/*
169 * Message handlers.
170 */
171
172/* {{{ static int mo_hurt()
173 *
174 * HURT [<expire>] <ip> <reason>
55abcbb2 175 *
212380e3
AC
176 * parv[1] - expire or ip
177 * parv[2] - ip or reason
178 * parv[3] - reason or NULL
179 */
180static int
760bafda 181mo_hurt(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
182 int parc, const char **parv)
183{
184 const char *ip, *expire, *reason;
185 int expire_time;
186 hurt_t *hurt;
187 struct Client *target_p;
188
189 if (!IsOperK(source_p)) {
190 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
191 source_p->name, "kline");
192 return 0;
193 }
194
195 if (parc == 3)
196 expire = NULL, ip = parv[1], reason = parv[2];
197 else
198 expire = parv[1], ip = parv[2], reason = parv[3];
199
200 if (!expire)
201 expire_time = HURT_DEFAULT_EXPIRE;
202 if (expire && (expire_time = valid_temp_time(expire)) < 1) {
5366977b 203 sendto_one_notice(source_p, ":Permanent HURTs are not supported");
212380e3
AC
204 return 0;
205 }
206 if (EmptyString(reason)) {
5366977b 207 sendto_one_notice(source_p, ":Empty HURT reasons are bad for business");
212380e3
AC
208 return 0;
209 }
210
211 /* Is this a client? */
212 if (strchr(ip, '.') == NULL && strchr(ip, ':') == NULL)
213 {
214 target_p = find_named_person(ip);
215 if (target_p == NULL)
216 {
217 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
218 form_str(ERR_NOSUCHNICK), ip);
219 return 0;
220 }
221 ip = target_p->orighost;
222 }
223 else
224 {
225 if (!strncmp(ip, "*@", 2))
226 ip += 2;
227 if (strchr(ip, '!') || strchr(ip, '@'))
228 {
229 sendto_one_notice(source_p, ":Invalid HURT mask [%s]",
230 ip);
231 return 0;
232 }
233 }
234
235 if (hurt_find(ip) != NULL) {
5366977b 236 sendto_one(source_p, ":[%s] already HURT", ip);
212380e3
AC
237 return 0;
238 }
239
240 /*
241 * okay, we've got this far, now it's time to add the the HURT locally
242 * and propagate it to other servers on the network.
243 */
244 sendto_realops_snomask(SNO_GENERAL, L_ALL,
245 "%s added HURT on [%s] for %ld minutes with reason [%s]",
246 get_oper_name(source_p), ip, (long) expire_time / 60, reason);
247
248 hurt = hurt_new(expire_time, ip, reason);
249 hurt_add(hurt);
250 hurt_propagate(NULL, source_p, hurt);
251
252 return 0;
253}
254/* }}} */
255
256/* {{{ static int me_hurt()
257 *
258 * [ENCAP mask] HURT <target> <expire> <ip> <reason>
259 *
260 * parv[1] - expire
261 * parv[2] - ip
262 * parv[3] - reason
263 */
264static int
760bafda 265me_hurt(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
266 int parc, const char **parv)
267{
268 time_t expire_time;
269 hurt_t *hurt;
270
271 /*
272 * right... if we don't get enough arguments, or if we get any invalid
273 * arguments, just ignore this request - shit happens, and it's not worth
274 * dropping a server over.
275 */
276 if (parc < 4 || !IsPerson(source_p))
277 return 0;
278 if ((expire_time = atoi(parv[1])) < 1)
279 return 0;
280 if (hurt_find(parv[2]) != NULL)
281 return 0;
282 if (EmptyString(parv[3]))
283 return 0;
284
285 sendto_realops_snomask(SNO_GENERAL, L_ALL,
286 "%s added HURT on [%s] for %ld minutes with reason [%s]",
287 get_oper_name(source_p), parv[2], (long) expire_time / 60, parv[3]);
288 hurt = hurt_new(expire_time, parv[2], parv[3]);
289 hurt_add(hurt);
290
291 return 0;
292}
293/* }}} */
294
295/* {{{ static int mo_heal()
296 *
297 * HURT <nick>|<ip>
298 *
299 * parv[1] - nick or ip
300 */
301static int
760bafda 302mo_heal(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
303 int parc, const char **parv)
304{
305 struct Client *target_p;
306
307 if (!IsOperUnkline(source_p))
308 {
309 sendto_one(source_p, form_str(ERR_NOPRIVS),
310 me.name, source_p->name, "unkline");
311 return 0;
312 }
313
2d28539c 314 if (clean_nick(parv[1], 0))
212380e3
AC
315 {
316 target_p = find_named_person(parv[1]);
317 if (target_p == NULL)
318 {
319 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
320 form_str(ERR_NOSUCHNICK), parv[1]);
321 return 0;
322 }
323 if (MyConnect(target_p))
324 heal_nick(source_p, target_p);
325 else
326 sendto_one(target_p, ":%s ENCAP %s HEAL %s",
327 get_id(source_p, target_p),
328 target_p->servptr->name,
329 get_id(target_p, target_p));
330 }
331 else if (strchr(parv[1], '.'))
332 {
333 if (hurt_find_exact(parv[1]) == NULL)
334 {
5366977b 335 sendto_one_notice(source_p, ":Mask [%s] is not HURT", parv[1]);
212380e3
AC
336 return 0;
337 }
338 hurt_remove(parv[1]);
339 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s removed HURT on %s",
340 get_oper_name(source_p), parv[1]);
341 sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s ENCAP * HEAL %s",
342 source_p->name, parv[1]);
343 }
344 else
345 {
5366977b 346 sendto_one(source_p, ":[%s] is not a valid IP address/nick", parv[1]);
212380e3
AC
347 return 0;
348 }
349
350 return 0;
351}
352/* }}} */
353
354static int
760bafda 355me_heal(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
356 int parc, const char **parv)
357{
358 struct Client *target_p;
359
360 /* as noted in me_hurt(), if we don't get sufficient arguments...
361 * *poof*, it's dropped...
362 */
363 if (parc < 2)
364 return 0;
365
2d28539c 366 if (clean_nick(parv[1], 0))
212380e3
AC
367 {
368 target_p = find_person(parv[1]);
369 if (target_p != NULL && MyConnect(target_p))
370 heal_nick(source_p, target_p);
371 }
372 else if (strchr(parv[1], '.')) /* host or mask to remove ban for */
373 {
374 if (hurt_find_exact(parv[1]) == NULL)
375 return 0;
376
377 hurt_remove(parv[1]);
378 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s removed HURT on %s",
379 get_oper_name(source_p), parv[1]);
380 }
381 else
382 return 0;
383
384 return 0;
385}
386
387/*
388 * Event handlers.
389 */
390
391/* {{{ static void hurt_check_event() */
392static void
393hurt_check_event(void *arg)
394{
ddcb223e 395 rb_dlink_node *ptr, *next_ptr;
212380e3
AC
396 struct Client *client_p;
397
ddcb223e 398 RB_DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_state.hurt_clients.head) {
212380e3
AC
399 client_p = ptr->data;
400 if (!EmptyString(client_p->user->suser))
401 {
ddcb223e 402 rb_dlinkDestroy(ptr, &hurt_state.hurt_clients);
212380e3 403 sendto_one_notice(client_p, ":HURT restriction removed for this session");
954012d3 404 client_p->localClient->target_last = rb_current_time(); /* don't ask --nenolod */
212380e3
AC
405 }
406 else if (client_p->localClient->receiveM > hurt_state.cutoff)
407 exit_client(NULL, client_p, &me, hurt_state.exit_reason);
408 }
409}
410/* }}} */
411
412/* {{{ static void hurt_expire_event() */
413static void
414hurt_expire_event(void *unused)
415{
ddcb223e 416 rb_dlink_node *ptr, *next_ptr;
212380e3
AC
417 hurt_t *hurt;
418
ddcb223e 419 RB_DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_confs.head)
212380e3
AC
420 {
421 hurt = (hurt_t *) ptr->data;
422
954012d3 423 if (hurt->expire <= rb_current_time())
212380e3 424 {
ddcb223e 425 rb_dlinkFindDestroy(hurt, &hurt_confs);
212380e3
AC
426 hurt_destroy(hurt);
427 }
428 }
429}
430/* }}} */
431
432/*
433 * Hook functions.
434 */
435
436/* {{{ static void client_exit_hook() */
437static void
438client_exit_hook(hook_data_client_exit *data)
439{
440 s_assert(data != NULL);
441 s_assert(data->target != NULL);
442
ddcb223e 443 rb_dlinkFindDestroy(data->target, &hurt_state.hurt_clients);
212380e3
AC
444}
445/* }}} */
446
447/* {{{ static void new_local_user_hook() */
448static void
449new_local_user_hook(struct Client *source_p)
450{
451 if (IsAnyDead(source_p) || !EmptyString(source_p->user->suser) ||
452 IsExemptKline(source_p))
453 return;
454
455 if (hurt_find(source_p->sockhost) || hurt_find(source_p->orighost))
456 {
954012d3 457 source_p->localClient->target_last = rb_current_time() + 600; /* don't ask --nenolod */
212380e3 458 SetTGChange(source_p);
ddcb223e 459 rb_dlinkAddAlloc(source_p, &hurt_state.hurt_clients);
212380e3 460 sendto_one_notice(source_p, ":You are hurt. Please identify to services immediately, or use /stats p for assistance.");
55abcbb2 461 }
212380e3
AC
462}
463/* }}} */
464
465/* {{{ static void doing_stats_hook() */
466static void
467doing_stats_hook(hook_data_int *hdata)
468{
ddcb223e 469 rb_dlink_node *ptr;
212380e3
AC
470 hurt_t *hurt;
471 struct Client *source_p;
472
473 s_assert(hdata);
474 s_assert(hdata->client);
475
476 source_p = hdata->client;
477 if(hdata->arg2 != (int) 's')
478 return;
479 if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
480 return;
481 if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
482 {
483 hurt = hurt_find(source_p->sockhost);
484 if (hurt != NULL)
485 {
486 sendto_one_numeric(source_p, RPL_STATSKLINE,
487 form_str(RPL_STATSKLINE), 's',
488 "*", hurt->ip, hurt->reason, "", "");
489 return;
490 }
491
492 hurt = hurt_find(source_p->orighost);
493 if (hurt != NULL)
494 {
495 sendto_one_numeric(source_p, RPL_STATSKLINE,
496 form_str(RPL_STATSKLINE), 's',
497 "*", hurt->ip, hurt->reason, "", "");
498 return;
499 }
500 return;
501 }
502
ddcb223e 503 RB_DLINK_FOREACH(ptr, hurt_confs.head)
212380e3
AC
504 {
505 hurt = (hurt_t *) ptr->data;
506 sendto_one_numeric(source_p, RPL_STATSKLINE,
507 form_str(RPL_STATSKLINE), 's',
508 "*", hurt->ip, hurt->reason, "", "");
509 }
510}
511/* }}} */
512
513/* {{{ static void hurt_propagate()
514 *
515 * client_p - specific server to propagate HURT to, or NULL to propagate to all
516 * servers.
517 * source_p - source (oper who added the HURT)
518 * hurt - HURT to be propagated
519 */
520static void
521hurt_propagate(struct Client *client_p, struct Client *source_p, hurt_t *hurt)
522{
523 if (client_p)
524 sendto_one(client_p,
525 ":%s ENCAP %s HURT %ld %s :%s",
526 source_p->name, client_p->name,
954012d3 527 (long)(hurt->expire - rb_current_time()),
212380e3
AC
528 hurt->ip, hurt->reason);
529 else
530 sendto_server(&me, NULL, NOCAPS, NOCAPS,
531 ":%s ENCAP * HURT %ld %s :%s",
532 source_p->name,
954012d3 533 (long)(hurt->expire - rb_current_time()),
212380e3
AC
534 hurt->ip, hurt->reason);
535}
536/* }}} */
537
538/* {{{ static hurt_t *hurt_new() */
539static hurt_t *
540hurt_new(time_t expire, const char *ip, const char *reason)
541{
542 hurt_t *hurt;
543
b42e202d 544 hurt = rb_malloc(sizeof(hurt_t));
212380e3 545
b42e202d
VY
546 hurt->ip = rb_strdup(ip);
547 hurt->reason = rb_strdup(reason);
954012d3 548 hurt->expire = rb_current_time() + expire;
212380e3
AC
549
550 return hurt;
551}
552/* }}} */
553
554/* {{{ static void hurt_destroy() */
555static void
556hurt_destroy(void *hurt)
557{
558 hurt_t *h;
559
560 if (!hurt)
561 return;
562
563 h = (hurt_t *) hurt;
b42e202d
VY
564 rb_free(h->ip);
565 rb_free(h->reason);
566 rb_free(h);
212380e3
AC
567}
568/* }}} */
569
570static void
571hurt_add(hurt_t *hurt)
572{
ddcb223e 573 rb_dlinkAddAlloc(hurt, &hurt_confs);
212380e3
AC
574}
575
576static hurt_t *
577hurt_find_exact(const char *ip)
578{
ddcb223e 579 rb_dlink_node *ptr;
212380e3
AC
580 hurt_t *hurt;
581
ddcb223e 582 RB_DLINK_FOREACH(ptr, hurt_confs.head)
212380e3
AC
583 {
584 hurt = (hurt_t *) ptr->data;
585
586 if (!strcasecmp(ip, hurt->ip))
587 return hurt;
588 }
589
590 return NULL;
591}
592
593static hurt_t *
594hurt_find(const char *ip)
595{
ddcb223e 596 rb_dlink_node *ptr;
212380e3
AC
597 hurt_t *hurt;
598
ddcb223e 599 RB_DLINK_FOREACH(ptr, hurt_confs.head)
212380e3
AC
600 {
601 hurt = (hurt_t *) ptr->data;
602
603 if (match(hurt->ip, ip))
604 return hurt;
605 }
606
607 return NULL;
608}
609
610static void
611hurt_remove(const char *ip)
612{
613 hurt_t *hurt = hurt_find_exact(ip);
614
ddcb223e 615 rb_dlinkFindDestroy(hurt, &hurt_confs);
212380e3
AC
616 hurt_destroy(hurt);
617}
618
619/* {{{ static int heal_nick() */
620static int
621heal_nick(struct Client *source_p, struct Client *target_p)
622{
ddcb223e 623 if (rb_dlinkFindDestroy(target_p, &hurt_state.hurt_clients))
212380e3
AC
624 {
625 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s used HEAL on %s",
626 get_oper_name(source_p), get_client_name(target_p, HIDE_IP));
627 sendto_one_notice(target_p, ":HURT restriction temporarily removed by operator");
628 sendto_one_notice(source_p, ":HURT restriction on %s temporarily removed", target_p->name);
954012d3 629 target_p->localClient->target_last = rb_current_time(); /* don't ask --nenolod */
212380e3
AC
630 return 1;
631 }
632 else
633 {
634 sendto_one_notice(source_p, ":%s was not hurt", target_p->name);
635 return 0;
636 }
637}
638/* }}} */
639
212380e3
AC
640/*
641 * vim: ts=8 sw=8 noet fdm=marker tw=80
642 */