diff --git a/doc/reference.conf b/doc/reference.conf index ce283109..6074ed0f 100755 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -1030,10 +1030,10 @@ general { */ warn_no_nline = yes; - /* use propagated bans: KLINE sets fully propagated bans. That means - * the klines are part of the netburst and restarted/split servers - * will get them, but they will not apply to 3.2 and older servers - * at all. + /* use propagated bans: KLINE and XLINE set fully propagated bans. + * That means the bans are part of the netburst and restarted/split + * servers will get them, but they will not apply to 3.2 and older + * servers at all. */ use_propagated_bans = yes; diff --git a/help/opers/stats b/help/opers/stats index 5d25900d..f20ad564 100644 --- a/help/opers/stats +++ b/help/opers/stats @@ -36,7 +36,7 @@ X f - Shows File Descriptors * U - Shows shared blocks (Old U: lines) u - Shows server uptime ^ v - Shows connected servers and brief status information -* x - Shows temporary gecos bans +* x - Shows temporary and global gecos bans * X - Shows gecos bans (Old X: lines) ^ y - Shows connection classes (Old Y: lines) * z - Shows memory stats diff --git a/include/s_conf.h b/include/s_conf.h index 03d78a66..b1124f0b 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -327,6 +327,7 @@ extern void free_conf(struct ConfItem *); extern rb_dlink_node *find_prop_ban(unsigned int status, const char *user, const char *host); extern void deactivate_conf(struct ConfItem *, rb_dlink_node *); +extern void replace_old_ban(struct ConfItem *); extern void read_conf_files(int cold); diff --git a/modules/core/m_ban.c b/modules/core/m_ban.c index f61ba076..0efe6ef3 100644 --- a/modules/core/m_ban.c +++ b/modules/core/m_ban.c @@ -89,6 +89,10 @@ ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *p ntype = CONF_KILL; stype = "K-Line"; break; + case 'X': + ntype = CONF_XLINE; + stype = "X-Line"; + break; default: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unknown BAN type %s from %s", @@ -199,10 +203,12 @@ ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *p aconf->user ? "@" : "", aconf->host, parv[parc - 1]); - ilog(L_KLINE, "%s %s %d %s %s %s", parv[1], + ilog(L_KLINE, "%s %s %d %s%s%s %s", parv[1], IsServer(source_p) ? source_p->name : get_oper_name(source_p), (hold - rb_current_time()) / 60, - aconf->user, aconf->host, + aconf->user ? aconf->user : "", + aconf->user ? " " : "", + aconf->host, parv[parc - 1]); aconf->status &= ~CONF_ILLEGAL; } @@ -217,9 +223,11 @@ ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *p aconf->host, strcmp(parv[7], "*") ? " on behalf of " : "", strcmp(parv[7], "*") ? parv[7] : ""); - ilog(L_KLINE, "U%s %s %s %s", parv[1], + ilog(L_KLINE, "U%s %s %s%s %s", parv[1], IsServer(source_p) ? source_p->name : get_oper_name(source_p), - aconf->user, aconf->host); + aconf->user ? aconf->user : "", + aconf->user ? " " : "", + aconf->host); } switch (ntype) { @@ -244,6 +252,15 @@ ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *p check_klines(); } break; + case CONF_XLINE: + if (aconf->status & CONF_ILLEGAL) + remove_reject_mask(aconf->host, NULL); + else + { + rb_dlinkAddAlloc(aconf, &xline_conf_list); + check_xlines(); + } + break; } sendto_server(client_p, NULL, CAP_BAN|CAP_TS6, NOCAPS, ":%s BAN %s %s %s %s %s %s %s :%s", diff --git a/modules/m_kline.c b/modules/m_kline.c index 364c30b0..d6e22bc5 100644 --- a/modules/m_kline.c +++ b/modules/m_kline.c @@ -584,32 +584,11 @@ static void apply_prop_kline(struct Client *source_p, struct ConfItem *aconf, const char *reason, const char *oper_reason, int tkline_time) { - rb_dlink_node *ptr; - struct ConfItem *oldconf; - aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY; aconf->hold = rb_current_time() + tkline_time; aconf->lifetime = aconf->hold; - ptr = find_prop_ban(aconf->status, aconf->user, aconf->host); - if(ptr != NULL) - { - oldconf = ptr->data; - /* Remember at least as long as the old one. */ - if(oldconf->lifetime > aconf->lifetime) - aconf->lifetime = oldconf->lifetime; - /* Force creation time to increase. */ - if(oldconf->created >= aconf->created) - aconf->created = oldconf->created + 1; - /* Leave at least one second of validity. */ - if(aconf->hold <= aconf->created) - aconf->hold = aconf->created + 1; - if(aconf->lifetime < aconf->hold) - aconf->lifetime = aconf->hold; - /* Tell deactivate_conf() to destroy it. */ - oldconf->lifetime = rb_current_time(); - deactivate_conf(oldconf, ptr); - } + replace_old_ban(aconf); rb_dlinkAddAlloc(aconf, &prop_bans); add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf); diff --git a/modules/m_xline.c b/modules/m_xline.c index 556ad005..566a3692 100644 --- a/modules/m_xline.c +++ b/modules/m_xline.c @@ -79,7 +79,7 @@ DECLARE_MODULE_AV1(xline, NULL, NULL, xline_clist, NULL, NULL, "$Revision$"); static int valid_xline(struct Client *, const char *, const char *); static void apply_xline(struct Client *client_p, const char *name, - const char *reason, int temp_time); + const char *reason, int temp_time, int propagated); static void propagate_xline(struct Client *source_p, const char *target, int temp_time, const char *name, const char *type, const char *reason); static void cluster_xline(struct Client *source_p, int temp_time, @@ -89,7 +89,8 @@ static void handle_remote_xline(struct Client *source_p, int temp_time, const char *name, const char *reason); static void handle_remote_unxline(struct Client *source_p, const char *name); -static void remove_xline(struct Client *source_p, const char *name); +static void remove_xline(struct Client *source_p, const char *name, + int propagated); /* m_xline() @@ -107,6 +108,7 @@ mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char const char *target_server = NULL; int temp_time; int loc = 1; + int propagated = ConfigFileEntry.use_propagated_bans; if(!IsOperXline(source_p)) { @@ -152,8 +154,11 @@ mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char if(!match(target_server, me.name)) return 0; + + /* Set as local-only. */ + propagated = 0; } - else if(rb_dlink_list_length(&cluster_conf_list) > 0) + else if(!propagated && rb_dlink_list_length(&cluster_conf_list) > 0) cluster_xline(source_p, temp_time, name, reason); if((aconf = find_xline_mask(name)) != NULL) @@ -166,7 +171,13 @@ mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char if(!valid_xline(source_p, name, reason)) return 0; - apply_xline(source_p, name, reason, temp_time); + if(propagated && temp_time == 0) + { + sendto_one_notice(source_p, ":Cannot set a permanent global ban"); + return 0; + } + + apply_xline(source_p, name, reason, temp_time, propagated); return 0; } @@ -226,7 +237,7 @@ handle_remote_xline(struct Client *source_p, int temp_time, const char *name, co return; } - apply_xline(source_p, name, reason, temp_time); + apply_xline(source_p, name, reason, temp_time, 0); } /* valid_xline() @@ -270,8 +281,9 @@ valid_xline(struct Client *source_p, const char *gecos, const char *reason) } void -apply_xline(struct Client *source_p, const char *name, const char *reason, int temp_time) +apply_xline(struct Client *source_p, const char *name, const char *reason, int temp_time, int propagated) { + rb_dlink_node *ptr; struct ConfItem *aconf; aconf = make_conf(); @@ -283,7 +295,32 @@ apply_xline(struct Client *source_p, const char *name, const char *reason, int t aconf->info.oper = operhash_add(get_oper_name(source_p)); - if(temp_time > 0) + if(propagated) + { + aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY; + aconf->hold = rb_current_time() + temp_time; + aconf->lifetime = aconf->hold; + + replace_old_ban(aconf); + rb_dlinkAddAlloc(aconf, &prop_bans); + + sendto_realops_snomask(SNO_GENERAL, L_ALL, + "%s added global %d min. X-Line for [%s] [%s]", + get_oper_name(source_p), temp_time / 60, + aconf->host, reason); + ilog(L_KLINE, "X %s %d %s %s", + get_oper_name(source_p), temp_time / 60, name, reason); + sendto_one_notice(source_p, ":Added global %d min. X-Line [%s]", + temp_time / 60, aconf->host); + sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS, + ":%s BAN X * %s %lu %d %d * :%s", + source_p->id, aconf->host, + (unsigned long)aconf->created, + (int)(aconf->hold - aconf->created), + (int)(aconf->lifetime - aconf->created), + reason); + } + else if(temp_time > 0) { aconf->hold = rb_current_time() + temp_time; @@ -366,6 +403,8 @@ cluster_xline(struct Client *source_p, int temp_time, const char *name, const ch static int mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { + int propagated = 1; + if(!IsOperXline(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "xline"); @@ -385,11 +424,12 @@ mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const cha if(match(parv[3], me.name) == 0) return 0; - } - else if(rb_dlink_list_length(&cluster_conf_list)) - cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER, "%s", parv[1]); - remove_xline(source_p, parv[1]); + propagated = 0; + } + /* cluster{} moved to remove_xline */ + + remove_xline(source_p, parv[1], propagated); return 0; } @@ -434,13 +474,13 @@ handle_remote_unxline(struct Client *source_p, const char *name) source_p->servptr->name, SHARED_UNXLINE)) return; - remove_xline(source_p, name); + remove_xline(source_p, name, 0); return; } static void -remove_xline(struct Client *source_p, const char *name) +remove_xline(struct Client *source_p, const char *name, int propagated) { struct ConfItem *aconf; rb_dlink_node *ptr; @@ -451,6 +491,41 @@ remove_xline(struct Client *source_p, const char *name) if(!irccmp(aconf->host, name)) { + if(aconf->lifetime) + { + if(!propagated) + { + sendto_one_notice(source_p, ":Cannot remove global X-Line %s on specific servers", name); + return; + } + ptr = rb_dlinkFind(aconf, &prop_bans); + if(ptr == NULL) + return; + sendto_one_notice(source_p, ":X-Line for [%s] is removed", name); + sendto_realops_snomask(SNO_GENERAL, L_ALL, + "%s has removed the global X-Line for: [%s]", + get_oper_name(source_p), name); + ilog(L_KLINE, "UX %s %s", get_oper_name(source_p), name); + if(aconf->created < rb_current_time()) + aconf->created = rb_current_time(); + else + aconf->created++; + aconf->hold = aconf->created; + operhash_delete(aconf->info.oper); + aconf->info.oper = operhash_add(get_oper_name(source_p)); + aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY; + sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS, + ":%s BAN X * %s %lu %d %d * :*", + source_p->id, aconf->host, + (unsigned long)aconf->created, + 0, + (int)(aconf->lifetime - aconf->created)); + remove_reject_mask(aconf->host, NULL); + deactivate_conf(aconf, ptr); + return; + } + else if(MyClient(source_p) && rb_dlink_list_length(&cluster_conf_list)) + cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER, "%s", name); if(!aconf->hold) { bandb_del(BANDB_XLINE, aconf->host, NULL); @@ -477,6 +552,9 @@ remove_xline(struct Client *source_p, const char *name) } } + if(MyClient(source_p) && rb_dlink_list_length(&cluster_conf_list)) + cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER, "%s", name); + sendto_one_notice(source_p, ":No X-Line for %s", name); return; diff --git a/src/s_conf.c b/src/s_conf.c index 11d2d0a1..cfd6048d 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -1064,6 +1064,36 @@ deactivate_conf(struct ConfItem *aconf, rb_dlink_node *ptr) } } +/* Given a new ban ConfItem, look for any matching ban, update the lifetime + * from it and delete it. + */ +void +replace_old_ban(struct ConfItem *aconf) +{ + rb_dlink_node *ptr; + struct ConfItem *oldconf; + + ptr = find_prop_ban(aconf->status, aconf->user, aconf->host); + if(ptr != NULL) + { + oldconf = ptr->data; + /* Remember at least as long as the old one. */ + if(oldconf->lifetime > aconf->lifetime) + aconf->lifetime = oldconf->lifetime; + /* Force creation time to increase. */ + if(oldconf->created >= aconf->created) + aconf->created = oldconf->created + 1; + /* Leave at least one second of validity. */ + if(aconf->hold <= aconf->created) + aconf->hold = aconf->created + 1; + if(aconf->lifetime < aconf->hold) + aconf->lifetime = aconf->hold; + /* Tell deactivate_conf() to destroy it. */ + oldconf->lifetime = rb_current_time(); + deactivate_conf(oldconf, ptr); + } +} + static void expire_prop_bans(void *list) {