2 * syn: a utility bot to manage IRC network access
3 * Copyright (C) 2009-2016 Stephen Bennett
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 mowgli_patricia_t
*ircd_klines
;
26 mowgli_list_t ircd_wildcard_klines
;
27 mowgli_heap_t
*ircd_kline_heap
;
29 mowgli_eventloop_timer_t
*expire_timer
= 0;
31 static void syn_m_kline(sourceinfo_t
*si
, int parc
, char **parv
);
32 static void syn_m_ban(sourceinfo_t
*si
, int parc
, char **parv
);
33 static void syn_m_unkline(sourceinfo_t
*si
, int parc
, char **parv
);
34 static void expire_klines(void *unused
);
36 char *kline_kill_reason
= 0;
38 static void mod_init(module_t
*m
)
40 use_syn_main_symbols(m
);
42 ircd_klines
= mowgli_patricia_create(noopcanon
);
43 ircd_kline_heap
= mowgli_heap_create(sizeof(kline_t
), 512, BH_NOW
);
45 hook_add_event("syn_kline_added");
47 add_dupstr_conf_item("KLINE_KILL_REASON", &syn
->conf_table
, 0, &kline_kill_reason
, "Banned");
49 pcommand_add("KLINE", syn_m_kline
, 5, MSRC_USER
);
50 pcommand_add("BAN", syn_m_ban
, 8, MSRC_USER
| MSRC_SERVER
);
51 pcommand_add("UNKLINE", syn_m_unkline
, 3, MSRC_USER
);
53 expire_timer
= mowgli_timer_add(base_eventloop
, "expire_ircd_klines", expire_klines
, NULL
, 120);
56 static void mod_deinit(module_unload_intent_t intent
)
58 pcommand_delete("KLINE");
59 pcommand_delete("BAN");
60 pcommand_delete("UNKLINE");
61 mowgli_timer_destroy(base_eventloop
, expire_timer
);
64 kline_t
* _syn_find_kline(const char *user
, const char *host
)
67 if ((k
= mowgli_patricia_retrieve(ircd_klines
, host
)))
71 MOWGLI_LIST_FOREACH(n
, ircd_wildcard_klines
.head
)
74 if (0 == match(k
->host
, host
))
76 if (0 == match_ips(k
->host
, host
))
82 static void syn_add_kline(const char *setter
, const char *user
, const char *host
, int duration
, const char *reason
)
84 if (_syn_find_kline(user
, host
))
86 syn_debug(3, "Duplicate K:line %s@%s", user
, host
);
90 if (host
[0] == '*' && host
[1] == '\0')
92 wallops("%s is an idiot. Dropping *@* kline.", setter
);
96 kline_t
*k
= mowgli_heap_alloc(ircd_kline_heap
);
97 k
->duration
= duration
;
98 k
->settime
= CURRTIME
;
99 k
->expires
= CURRTIME
+ k
->duration
;
100 k
->user
= sstrdup(user
);
101 k
->host
= sstrdup(host
);
102 k
->reason
= sstrdup(reason
);
105 if (NULL
!= (p
= strchr(k
->reason
, '|')))
110 if (strchr(k
->host
, '*') || strchr(k
->host
, '?') || (strchr(k
->host
, '/') && valid_ip_or_mask(k
->host
)))
112 mowgli_node_t
*n
= mowgli_node_create();
113 mowgli_node_add(k
, n
, &ircd_wildcard_klines
);
117 mowgli_patricia_add(ircd_klines
, k
->host
, k
);
120 hook_call_event("syn_kline_added", k
);
122 syn_debug(1, "Added K:line %s@%s (%s)", k
->user
, k
->host
, k
->reason
);
125 static void syn_remove_kline(const char *user
, const char *host
)
127 mowgli_node_t
*n
, *tn
;
130 kline_t
*removed
= mowgli_patricia_delete(ircd_klines
, host
);
133 syn_debug(1, "Removing K:line on %s@%s", removed
->user
, removed
->host
);
136 free(removed
->reason
);
137 mowgli_heap_free(ircd_kline_heap
, removed
);
141 MOWGLI_LIST_FOREACH_SAFE(n
, tn
, ircd_wildcard_klines
.head
)
143 k
= (kline_t
*) n
->data
;
144 if (0 == strcasecmp(k
->user
, user
) &&
145 0 == strcasecmp(k
->host
, host
))
147 syn_debug(1, "Removing K:line on %s@%s", k
->user
, k
->host
);
148 mowgli_node_delete(n
, &ircd_wildcard_klines
);
152 mowgli_heap_free(ircd_kline_heap
, k
);
157 static void expire_klines(void *unused
)
159 mowgli_node_t
*n
, *tn
;
162 MOWGLI_LIST_FOREACH_SAFE(n
, tn
, ircd_wildcard_klines
.head
)
164 k
= (kline_t
*) n
->data
;
166 if (k
->duration
== 0)
169 if (k
->expires
<= CURRTIME
)
171 syn_debug(1, "Expiring K:line on %s@%s", k
->user
, k
->host
);
172 mowgli_node_delete(n
, &ircd_wildcard_klines
);
176 mowgli_heap_free(ircd_kline_heap
, k
);
180 mowgli_patricia_iteration_state_t state
;
181 MOWGLI_PATRICIA_FOREACH(k
, &state
, ircd_klines
)
183 if (k
->duration
== 0)
185 if (k
->expires
<= CURRTIME
)
187 syn_debug(1, "Expiring K:line on %s@%s", k
->user
, k
->host
);
188 mowgli_patricia_delete(ircd_klines
, k
->host
);
192 mowgli_heap_free(ircd_kline_heap
, k
);
197 static void _syn_vkline(const char *host
, int duration
, const char *reason
, va_list ap
)
199 /* if (_syn_find_kline("*", host))
203 vsnprintf(buf
, BUFSIZE
, reason
, ap
);
205 kline_t
*k
= mowgli_heap_alloc(ircd_kline_heap
);
206 k
->duration
= duration
;
207 k
->settime
= CURRTIME
;
208 k
->expires
= CURRTIME
+ duration
;
209 k
->user
= sstrdup("*");
210 k
->host
= sstrdup(host
);
211 k
->reason
= sstrdup(buf
);
214 if (NULL
!= (p
= strchr(k
->reason
, '|')))
219 if (strchr(k
->host
, '*') || strchr(k
->host
, '?') || (strchr(k
->host
, '/') && valid_ip_or_mask(k
->host
)))
221 mowgli_node_t
*n
= mowgli_node_create();
222 mowgli_node_add(k
, n
, &ircd_wildcard_klines
);
226 mowgli_patricia_add(ircd_klines
, k
->host
, k
);
229 kline_sts("*", "*", k
->host
, k
->duration
, k
->reason
);
231 hook_call_event("syn_kline_added", k
);
233 syn_debug(1, "Added K:line %s@%s (%s)", k
->user
, k
->host
, k
->reason
);
236 void _syn_kline(const char *host
, int duration
, const char *reason
, ...)
239 va_start(ap
, reason
);
240 _syn_vkline(host
, duration
, reason
, ap
);
244 static void _syn_vkill(user_t
*victim
, const char *reason
, va_list ap
)
247 vsnprintf(buf
, BUFSIZE
, reason
, ap
);
248 notice(syn
->nick
, victim
->nick
, "%s", buf
);
249 kill_user(syn
->me
, victim
, "%s", kline_kill_reason
);
253 void _syn_kill(user_t
*victim
, const char *reason
, ...)
257 va_start(ap
, reason
);
258 _syn_vkill(victim
, reason
, ap
);
262 static void _syn_vkill2(user_t
*victim
, const char *killreason
, const char *reason
, va_list ap
)
265 vsnprintf(buf
, BUFSIZE
, reason
, ap
);
266 notice(syn
->nick
, victim
->nick
, "%s", buf
);
267 kill_user(syn
->me
, victim
, "%s", killreason
);
271 void _syn_kill2(user_t
*victim
, const char *killreason
, const char *reason
, ...)
275 va_start(ap
, reason
);
276 _syn_vkill2(victim
, killreason
, reason
, ap
);
280 void _syn_kill_or_kline(user_t
*victim
, int duration
, const char *reason
, ...)
283 va_start(ap
, reason
);
284 if (!victim
->ip
|| victim
->ip
[0] == '\0')
286 // No IP means an auth spoofed user, probably a gateway. Kill it instead.
287 // Don't give away the oper reason, though.
288 char user_reason
[BUFSIZE
];
289 strncpy(user_reason
, reason
, sizeof(user_reason
));
291 if (0 != (pipe
= strchr(user_reason
, '|')))
294 _syn_vkill(victim
, user_reason
, ap
);
298 _syn_vkline(victim
->ip
, duration
, reason
, ap
);
303 static void syn_m_kline(sourceinfo_t
*si
, int parc
, char **parv
)
305 syn_add_kline(si
->su
->nick
, parv
[2], parv
[3], atoi(parv
[1]), parv
[4]);
308 static void syn_m_unkline(sourceinfo_t
*si
, int parc
, char **parv
)
310 syn_remove_kline(parv
[1], parv
[2]);
313 static void syn_m_ban(sourceinfo_t
*si
, int parc
, char **parv
)
315 if (parv
[0][0] != 'K')
317 // Not a K:line; ignore
321 const char *user
= parv
[1], *host
= parv
[2], *setter
= parv
[6], *reason
= parv
[7];
322 int duration
= atoi(parv
[4]); // creation = atoi(parv[3]), lifetime = atoi(parv[5]);
324 if (setter
[0] == '*' && si
->su
)
325 setter
= si
->su
->nick
;
329 syn_add_kline(setter
, user
, host
, duration
, reason
);
333 syn_remove_kline(user
, host
);
339 "syn/kline", false, mod_init
, mod_deinit
,
341 "Stephen Bennett <stephen -at- freenode.net>"