5 static void masks_newuser(hook_user_nick_t
*data
);
7 static void syn_cmd_addmask(sourceinfo_t
*si
, int parc
, char **parv
);
8 static void syn_cmd_delmask(sourceinfo_t
*si
, int parc
, char **parv
);
9 static void syn_cmd_setmask(sourceinfo_t
*si
, int parc
, char **parv
);
10 static void syn_cmd_listmask(sourceinfo_t
*si
, int parc
, char **parv
);
12 command_t syn_addmask
= { "ADDMASK", N_("Adds a lethal, suspicious or exempt mask"), "syn:general", 1, syn_cmd_addmask
, { .path
= "syn/addmask" } };
13 command_t syn_delmask
= { "DELMASK", N_("Removes a lethal, suspicious or exempt mask"), "syn:general", 1, syn_cmd_delmask
, { .path
= "syn/delmask" } };
14 command_t syn_setmask
= { "SETMASK", N_("Modifies settings for a lethal, suspicious or exempt mask"), "syn:general", 1, syn_cmd_setmask
, { .path
= "syn/setmask" } };
15 command_t syn_listmask
= { "LISTMASK", N_("Displays configured mask lists"), "syn:general", 1, syn_cmd_listmask
, { .path
= "syn/listmask" } };
17 static unsigned int lethal_mask_duration
= 3600*24;
18 static char *lethal_mask_message
= NULL
;
20 static mowgli_eventloop_timer_t
*expire_masks_timer
;
40 char setter
[NICKLEN
*2+2];
48 } mask_string_map
[] = {
49 { "exempt", mask_exempt
},
50 { "suspicious", mask_suspicious
},
51 { "lethal", mask_lethal
},
55 const char *string_from_mask_type(mask_type t
)
57 for (int i
=0; mask_string_map
[i
].s
!= NULL
; ++i
)
58 if (mask_string_map
[i
].t
== t
)
59 return mask_string_map
[i
].s
;
63 mask_type
mask_type_from_string(const char *s
)
65 for (int i
=0; mask_string_map
[i
].s
!= NULL
; ++i
)
66 if (0 == strcasecmp(mask_string_map
[i
].s
, s
))
67 return mask_string_map
[i
].t
;
71 static void check_expiry(void *v
)
73 mowgli_node_t
*n
, *tn
;
74 MOWGLI_LIST_FOREACH_SAFE(n
, tn
, masks
.head
)
80 if (m
->expires
> CURRTIME
)
83 syn_report("Expiring %s mask \2%s\2", string_from_mask_type(m
->type
), m
->regex
);
87 mowgli_node_delete(n
, &masks
);
91 static void save_maskdb()
94 FILE *f
= fopen(DATADIR
"/masks.db", "w");
97 slog(LG_ERROR
, "Couldn't open masks.db for writing: %s", strerror(errno
));
101 MOWGLI_LIST_FOREACH(n
, masks
.head
)
105 fprintf(f
, "/%s/%s %d %s %lu %lu\n",
106 m
->regex
, m
->reflags
& AREGEX_ICASE
? "i" : "",
107 m
->type
, m
->setter
, m
->added
, m
->expires
);
112 static void load_maskdb()
114 FILE *f
= fopen(DATADIR
"/masks.db", "r");
117 slog(LG_DEBUG
, "Couldn't open masks db for reading: %s", strerror(errno
));
121 char line
[BUFSIZE
*2];
122 while(fgets(line
, sizeof(line
), f
))
126 char *regex
= regex_extract(args
, &args
, &flags
);
128 atheme_regex_t
*re
= regex_create(regex
, flags
);
132 slog(LG_DEBUG
, "Invalid entry %s in masks db", line
);
136 char setter
[BUFSIZE
*2];
138 time_t added
, expires
;
140 sscanf(args
, "%d %s %lu %lu", &type
, setter
, &added
, &expires
);
142 mask_t
*mask
= malloc(sizeof(mask_t
));
143 mask
->regex
= sstrdup(regex
);
144 mask
->reflags
= flags
;
146 strncpy(mask
->setter
, setter
, sizeof(mask
->setter
));
148 mask
->expires
= expires
;
151 mowgli_node_add(mask
, mowgli_node_create(), &masks
);
157 static void mod_init(module_t
*m
)
159 use_syn_main_symbols(m
);
160 use_syn_util_symbols(m
);
161 use_syn_kline_symbols(m
);
163 add_uint_conf_item("lethalmask_duration", &syn
->conf_table
, 0, &lethal_mask_duration
, 0, (unsigned int)-1, 3600*24);
164 add_dupstr_conf_item("lethalmask_message", &syn
->conf_table
, 0, &lethal_mask_message
, "Banned");
166 service_named_bind_command("syn", &syn_addmask
);
167 service_named_bind_command("syn", &syn_delmask
);
168 service_named_bind_command("syn", &syn_setmask
);
169 service_named_bind_command("syn", &syn_listmask
);
171 hook_add_event("user_nickchange");
172 hook_add_user_nickchange(masks_newuser
);
173 hook_add_event("user_add");
174 hook_add_user_add(masks_newuser
);
176 expire_masks_timer
= mowgli_timer_add(base_eventloop
, "masks_check_expiry", check_expiry
, NULL
, 60);
181 static void mod_deinit(module_unload_intent_t intent
)
185 service_named_unbind_command("syn", &syn_addmask
);
186 service_named_unbind_command("syn", &syn_delmask
);
187 service_named_unbind_command("syn", &syn_setmask
);
188 service_named_unbind_command("syn", &syn_listmask
);
190 del_conf_item("lethalmask_duration", &syn
->conf_table
);
191 del_conf_item("lethalmask_message", &syn
->conf_table
);
193 hook_del_user_add(masks_newuser
);
194 hook_del_user_nickchange(masks_newuser
);
196 mowgli_timer_destroy(base_eventloop
, expire_masks_timer
);
199 void masks_newuser(hook_user_nick_t
*data
)
203 /* If the user has already been killed, don't try to do anything */
207 char nuh
[NICKLEN
+USERLEN
+HOSTLEN
+GECOSLEN
];
208 snprintf(nuh
, sizeof(nuh
), "%s!%s@%s %s", u
->nick
, u
->user
, u
->host
, u
->gecos
);
210 int blocked
= 0, exempt
= 0;
211 char *suspicious_regex
= NULL
, *blocked_regex
= NULL
;
214 MOWGLI_LIST_FOREACH(n
, masks
.head
)
218 if (! regex_match(m
->re
, nuh
))
226 case mask_suspicious
:
227 suspicious_regex
= m
->regex
;
231 blocked_regex
= m
->regex
;
246 syn_report("Killing client %s(%s@%s) due to lethal mask %s",
247 u
->nick
, u
->user
, u
->host
, blocked_regex
);
248 syn_kill_or_kline(u
, lethal_mask_duration
, lethal_mask_message
);
253 if (suspicious_regex
)
255 syn_report("Client %s(%s@%s) matches suspicious mask %s",
256 u
->nick
, u
->user
, u
->host
, suspicious_regex
);
261 void syn_cmd_addmask(sourceinfo_t
*si
, int parc
, char **parv
)
270 char *args
= parv
[0];
274 command_fail(si
, fault_needmoreparams
, STR_INSUFFICIENT_PARAMS
, "ADDMASK");
275 command_fail(si
, fault_needmoreparams
, "Syntax: ADDMASK /<regex>/[i] <type>");
279 pattern
= regex_extract(args
, &args
, &flags
);
282 command_fail(si
, fault_badparams
, STR_INVALID_PARAMS
, "ADDMASK");
283 command_fail(si
, fault_badparams
, "Syntax: ADDMASK /<regex>/[i] <type>");
287 stype
= strtok(args
, " ");
289 if (!stype
|| *stype
== '\0')
291 command_fail(si
, fault_needmoreparams
, STR_INSUFFICIENT_PARAMS
, "ADDMASK");
292 command_fail(si
, fault_needmoreparams
, "Syntax: ADDMASK /<regex>/[i] <type>");
296 type
= mask_type_from_string(stype
);
297 if (type
== mask_unknown
)
299 command_fail(si
, fault_badparams
, "Invalid mask type \2%s\2.", stype
);
303 char *sduration
= strtok(NULL
, " ");
304 if (sduration
&& *sduration
== '~')
306 duration
= syn_parse_duration(++sduration
);
310 MOWGLI_LIST_FOREACH(n
, masks
.head
)
314 if (0 == strcmp(m
->regex
, pattern
))
316 command_fail(si
, fault_nochange
, "\2%s\2 was already added (%s); not re-adding", pattern
, string_from_mask_type(m
->type
));
321 atheme_regex_t
*regex
= regex_create(pattern
, flags
);
324 command_fail(si
, fault_badparams
, "The provided regex \2%s\2 is invalid.", pattern
);
328 newmask
= malloc(sizeof(mask_t
));
329 newmask
->regex
= sstrdup(pattern
);
330 newmask
->reflags
= flags
;
332 newmask
->type
= type
;
334 newmask
->expires
= CURRTIME
+ 60*duration
;
336 newmask
->expires
= 0;
338 newmask
->added
= CURRTIME
;
339 strncpy(newmask
->setter
, get_oper_name(si
), sizeof(newmask
->setter
));
341 mowgli_node_add(newmask
, mowgli_node_create(), &masks
);
343 syn_report("\002ADDMASK\002 /%s/%s (%s) by %s, expires %s",
344 pattern
, (flags
& AREGEX_ICASE
) ? "i" : "", stype
, get_oper_name(si
), syn_format_expiry(newmask
->expires
));
345 command_success_nodata(si
, "Added \2%s\2 to %s mask list, expiring %s.",
346 pattern
, stype
, syn_format_expiry(newmask
->expires
));
351 void syn_cmd_delmask(sourceinfo_t
*si
, int parc
, char **parv
)
353 char *args
= parv
[0];
357 command_fail(si
, fault_needmoreparams
, STR_INSUFFICIENT_PARAMS
, "DELMASK");
358 command_fail(si
, fault_needmoreparams
, "Syntax: DELMASK /<regex>/");
363 char *pattern
= regex_extract(args
, &args
, &flags
);
367 command_fail(si
, fault_badparams
, STR_INVALID_PARAMS
, "DELMASK");
368 command_fail(si
, fault_needmoreparams
, "Syntax: DELMASK /<regex>/");
372 mowgli_node_t
*n
, *tn
;
373 MOWGLI_LIST_FOREACH_SAFE(n
, tn
, masks
.head
)
376 if (0 == strcmp(pattern
, m
->regex
))
378 syn_report("\002DELMASK\002 /%s/%s (%s) by %s", pattern
, (m
->reflags
& AREGEX_ICASE
) ? "i" : "", string_from_mask_type(m
->type
), get_oper_name(si
));
379 command_success_nodata(si
, "Removing \2%s\2 from %s mask list", pattern
, string_from_mask_type(m
->type
));
380 regex_destroy(m
->re
);
383 mowgli_node_delete(n
, &masks
);
391 command_fail(si
, fault_nochange
, "\2%s\2 was not found in any mask list", pattern
);
394 void syn_cmd_setmask(sourceinfo_t
*si
, int parc
, char **parv
)
396 char *args
= parv
[0];
400 command_fail(si
, fault_needmoreparams
, STR_INSUFFICIENT_PARAMS
, "SETMASK");
401 command_fail(si
, fault_needmoreparams
, "Syntax: SETMASK /<regex>/ <type|~expiry>");
406 char *pattern
= regex_extract(args
, &args
, &flags
);
410 command_fail(si
, fault_badparams
, STR_INVALID_PARAMS
, "SETMASK");
411 command_fail(si
, fault_needmoreparams
, "Syntax: SETMASK /<regex>/ <type|~expiry>");
415 mowgli_node_t
*n
, *tn
;
417 MOWGLI_LIST_FOREACH_SAFE(n
, tn
, masks
.head
)
420 if (0 == strcmp(pattern
, m
->regex
))
427 command_fail(si
, fault_nochange
, "\2%s\2 was not found in any mask list", pattern
);
431 char *nextarg
= strtok(args
, " ");
435 command_fail(si
, fault_needmoreparams
, STR_INSUFFICIENT_PARAMS
, "SETMASK");
436 command_fail(si
, fault_needmoreparams
, "Syntax: SETMASK /<regex>/ <type|~expiry>");
440 mask_type t
= mask_type_from_string(nextarg
);
441 if (t
!= mask_unknown
)
444 syn_report("\002SETMASK\002 /%s/%s type->%s by %s", pattern
, (m
->reflags
& AREGEX_ICASE
) ? "i" : "", nextarg
, get_oper_name(si
));
445 command_success_nodata(si
, "Changed type of mask \2%s\2 to %s", pattern
, nextarg
);
454 time_t duration
= syn_parse_duration(++nextarg
);
457 m
->expires
= CURRTIME
+ duration
* 60;
458 syn_report("\002SETMASK\002 /%s/%s duration->%d by %s", pattern
, (m
->reflags
& AREGEX_ICASE
) ? "i" : "", duration
, get_oper_name(si
));
459 command_success_nodata(si
, "Changed expiry of mask \2%s\2 to %ld minutes", pattern
, duration
);
464 syn_report("\002SETMASK\002 /%s/%s expiry->off by %s", pattern
, (m
->reflags
& AREGEX_ICASE
) ? "i" : "", get_oper_name(si
));
465 command_success_nodata(si
, "Expiry disabled for mask \2%s\2.", pattern
);
473 command_fail(si
, fault_badparams
, STR_INVALID_PARAMS
, "SETMASK");
474 command_fail(si
, fault_badparams
, "Syntax: SETMASK /<regex>/ <type|~expiry>");
477 void syn_cmd_listmask(sourceinfo_t
*si
, int parc
, char **parv
)
479 mask_type t
= mask_unknown
;
483 t
= mask_type_from_string(parv
[0]);
489 MOWGLI_LIST_FOREACH(n
, masks
.head
)
493 if (t
!= mask_unknown
&& t
!= m
->type
)
497 strncpy(buf
, syn_format_expiry(m
->added
), BUFSIZE
);
498 command_success_nodata(si
, "\2/%s/%s\2 (%s), set by %s on %s, expires %s",
499 m
->regex
, (m
->reflags
& AREGEX_ICASE
) ? "i" : "", string_from_mask_type(m
->type
), m
->setter
,
500 buf
, syn_format_expiry(m
->expires
));
505 command_success_nodata(si
, "%d masks found", count
);
510 "syn/masks", false, mod_init
, mod_deinit
,
512 "Stephen Bennett <stephen -at- freenode.net>"