EBMASK capab, to burst BMASK metadata (#354)

This commit is contained in:
Jess Porter 2022-08-20 01:35:54 +01:00 committed by GitHub
parent a5192806a9
commit fdd8cad93f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 125 additions and 60 deletions

View file

@ -319,6 +319,21 @@ Sets a D:line (IP ban checked directly after accepting connection).
The mask must be an IP address or CIDR mask. The mask must be an IP address or CIDR mask.
EBMASK
source: server
propagation: broadcast
parameters: channelTS, channel, type, space separated "masks ts hostmask" chunks
If the channelTS in the message is greater (newer) than the current TS of
the channel, drop the message and do not propagate it.
Type is the mode letter of a ban-like mode. In efnet TS6 this is 'b', 'e' or
'I'. In charybdis TS6 additionally 'q' is possible.
Add all the masks and their set at/by to the given list of the channel.
All ban-like modes must be bursted using this command, not using MODE or TMODE.
ECHO ECHO
source: user source: user
parameters: "P"/"N", target, text parameters: "P"/"N", target, text

View file

@ -302,7 +302,7 @@ extern void set_channel_mlock(struct Client *client_p, struct Client *source_p,
extern struct ChannelMode chmode_table[256]; extern struct ChannelMode chmode_table[256];
extern bool add_id(struct Client *source_p, struct Channel *chptr, const char *banid, extern struct Ban * add_id(struct Client *source_p, struct Channel *chptr, const char *banid,
const char *forward, rb_dlink_list * list, long mode_type); const char *forward, rb_dlink_list * list, long mode_type);
extern struct Ban * del_id(struct Channel *chptr, const char *banid, rb_dlink_list * list, extern struct Ban * del_id(struct Channel *chptr, const char *banid, rb_dlink_list * list,

View file

@ -92,6 +92,7 @@ extern unsigned int CAP_EUID; /* supports EUID (ext UID + nonencap CHGHOST) */
extern unsigned int CAP_EOPMOD; /* supports EOPMOD (ext +z + ext topic) */ extern unsigned int CAP_EOPMOD; /* supports EOPMOD (ext +z + ext topic) */
extern unsigned int CAP_BAN; /* supports propagated bans */ extern unsigned int CAP_BAN; /* supports propagated bans */
extern unsigned int CAP_MLOCK; /* supports MLOCK messages */ extern unsigned int CAP_MLOCK; /* supports MLOCK messages */
extern unsigned int CAP_EBMASK; /* supports sending BMASK set by/at metadata */
/* XXX: added for backwards compatibility. --nenolod */ /* XXX: added for backwards compatibility. --nenolod */
#define CAP_MASK (capability_index_mask(serv_capindex) & ~(CAP_TS6 | CAP_CAP)) #define CAP_MASK (capability_index_mask(serv_capindex) & ~(CAP_TS6 | CAP_CAP))

View file

@ -237,10 +237,10 @@ allow_mode_change(struct Client *source_p, struct Channel *chptr, int alevel,
/* add_id() /* add_id()
* *
* inputs - client, channel, id to add, type, forward * inputs - client, channel, id to add, type, forward
* outputs - false on failure, true on success * outputs - NULL on failure, allocated Ban on success
* side effects - given id is added to the appropriate list * side effects - given id is added to the appropriate list
*/ */
bool struct Ban *
add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const char *forward, add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const char *forward,
rb_dlink_list * list, long mode_type) rb_dlink_list * list, long mode_type)
{ {
@ -256,7 +256,7 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
{ {
sendto_one(source_p, form_str(ERR_BANLISTFULL), sendto_one(source_p, form_str(ERR_BANLISTFULL),
me.name, source_p->name, chptr->chname, realban); me.name, source_p->name, chptr->chname, realban);
return false; return NULL;
} }
} }
@ -265,7 +265,7 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
{ {
actualBan = ptr->data; actualBan = ptr->data;
if(!irccmp(actualBan->banstr, realban)) if(!irccmp(actualBan->banstr, realban))
return false; return NULL;
} }
if(IsPerson(source_p)) if(IsPerson(source_p))
@ -282,7 +282,7 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
if(mode_type == CHFL_BAN || mode_type == CHFL_QUIET || mode_type == CHFL_EXCEPTION) if(mode_type == CHFL_BAN || mode_type == CHFL_QUIET || mode_type == CHFL_EXCEPTION)
chptr->bants = rb_current_time(); chptr->bants = rb_current_time();
return true; return actualBan;
} }
/* del_id() /* del_id()

View file

@ -86,6 +86,7 @@ unsigned int CAP_EUID;
unsigned int CAP_EOPMOD; unsigned int CAP_EOPMOD;
unsigned int CAP_BAN; unsigned int CAP_BAN;
unsigned int CAP_MLOCK; unsigned int CAP_MLOCK;
unsigned int CAP_EBMASK;
unsigned int CLICAP_MULTI_PREFIX; unsigned int CLICAP_MULTI_PREFIX;
unsigned int CLICAP_ACCOUNT_NOTIFY; unsigned int CLICAP_ACCOUNT_NOTIFY;
@ -126,6 +127,7 @@ init_builtin_capabs(void)
CAP_EOPMOD = capability_put(serv_capindex, "EOPMOD", NULL); CAP_EOPMOD = capability_put(serv_capindex, "EOPMOD", NULL);
CAP_BAN = capability_put(serv_capindex, "BAN", NULL); CAP_BAN = capability_put(serv_capindex, "BAN", NULL);
CAP_MLOCK = capability_put(serv_capindex, "MLOCK", NULL); CAP_MLOCK = capability_put(serv_capindex, "MLOCK", NULL);
CAP_EBMASK = capability_put(serv_capindex, "EBMASK", NULL);
capability_require(serv_capindex, "QS"); capability_require(serv_capindex, "QS");
capability_require(serv_capindex, "EX"); capability_require(serv_capindex, "EX");
@ -511,8 +513,9 @@ burst_modes_TS6(struct Client *client_p, struct Channel *chptr,
rb_dlink_node *ptr; rb_dlink_node *ptr;
struct Ban *banptr; struct Ban *banptr;
send_multiline_init(client_p, " ", ":%s BMASK %ld %s %c :", send_multiline_init(client_p, " ", ":%s %s %ld %s %c :",
me.id, me.id,
IsCapable(client_p, CAP_EBMASK) ? "EBMASK" : "BMASK",
(long)chptr->channelts, (long)chptr->channelts,
chptr->chname, chptr->chname,
flag); flag);
@ -522,11 +525,18 @@ burst_modes_TS6(struct Client *client_p, struct Channel *chptr,
banptr = ptr->data; banptr = ptr->data;
if (banptr->forward) if (banptr->forward)
send_multiline_item(client_p, "%s$%s", sprintf(buf, "%s$%s", banptr->banstr, banptr->forward);
banptr->banstr,
banptr->forward);
else else
send_multiline_item(client_p, "%s", banptr->banstr); strcpy(buf, banptr->banstr);
if IsCapable(client_p, CAP_EBMASK)
send_multiline_item(client_p, "%s %ld %s",
buf,
(long)banptr->when,
banptr->who);
else
send_multiline_item(client_p, "%s", buf);
} }
send_multiline_fini(client_p, NULL); send_multiline_fini(client_p, NULL);

View file

@ -48,6 +48,7 @@ static void ms_mode(struct MsgBuf *, struct Client *, struct Client *, int, cons
static void ms_tmode(struct MsgBuf *, struct Client *, struct Client *, int, const char **); static void ms_tmode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
static void ms_mlock(struct MsgBuf *, struct Client *, struct Client *, int, const char **); static void ms_mlock(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
static void ms_bmask(struct MsgBuf *, struct Client *, struct Client *, int, const char **); static void ms_bmask(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
static void ms_ebmask(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
struct Message mode_msgtab = { struct Message mode_msgtab = {
"MODE", 0, 0, 0, 0, "MODE", 0, 0, 0, 0,
@ -65,8 +66,12 @@ struct Message bmask_msgtab = {
"BMASK", 0, 0, 0, 0, "BMASK", 0, 0, 0, 0,
{mg_ignore, mg_ignore, mg_ignore, {ms_bmask, 5}, mg_ignore, mg_ignore} {mg_ignore, mg_ignore, mg_ignore, {ms_bmask, 5}, mg_ignore, mg_ignore}
}; };
struct Message ebmask_msgtab = {
"EBMASK", 0, 0, 0, 0,
{mg_ignore, mg_ignore, mg_ignore, {ms_ebmask, 5}, mg_ignore, mg_ignore}
};
mapi_clist_av1 mode_clist[] = { &mode_msgtab, &tmode_msgtab, &mlock_msgtab, &bmask_msgtab, NULL }; mapi_clist_av1 mode_clist[] = { &mode_msgtab, &tmode_msgtab, &mlock_msgtab, &bmask_msgtab, &ebmask_msgtab, NULL };
DECLARE_MODULE_AV2(mode, NULL, NULL, mode_clist, NULL, NULL, NULL, NULL, mode_desc); DECLARE_MODULE_AV2(mode, NULL, NULL, mode_clist, NULL, NULL, NULL, NULL, mode_desc);
@ -256,16 +261,19 @@ possibly_remove_lower_forward(struct Client *fakesource_p, int mems,
} }
static void static void
ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) do_bmask(bool extended, struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{ {
static char modebuf[BUFSIZE]; static char output[BUFSIZE];
static char parabuf[BUFSIZE]; static char parabuf[BUFSIZE];
static char degrade[BUFSIZE];
static char squitreason[120];
struct Channel *chptr; struct Channel *chptr;
struct Ban *banptr;
rb_dlink_list *banlist; rb_dlink_list *banlist;
char *s, *forward; char *s, *mask, *forward, *who;
char *t; char *output_ptr;
char *mbuf; char *param_ptr;
char *pbuf; char *degrade_ptr;
long mode_type; long mode_type;
int mlen; int mlen;
int plen = 0; int plen = 0;
@ -274,6 +282,7 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
int modecount = 0; int modecount = 0;
int needcap = NOCAPS; int needcap = NOCAPS;
int mems; int mems;
time_t when = (long)rb_current_time();
struct Client *fakesource_p; struct Client *fakesource_p;
if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2])) if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
@ -327,29 +336,29 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
fakesource_p = &me; fakesource_p = &me;
else else
fakesource_p = source_p; fakesource_p = source_p;
mlen = sprintf(modebuf, ":%s MODE %s +", fakesource_p->name, chptr->chname); who = fakesource_p->name;
mbuf = modebuf + mlen;
pbuf = parabuf; mlen = sprintf(output, ":%s MODE %s +", fakesource_p->name, chptr->chname);
output_ptr = output + mlen;
param_ptr = parabuf;
degrade_ptr = degrade;
while(*s == ' ') while(*s == ' ')
s++; s++;
/* next char isnt a space, point t to the next one */ s = strtok(s, " ");
if((t = strchr(s, ' ')) != NULL)
{
*t++ = '\0';
/* double spaces will break the parser */
while(*t == ' ')
t++;
}
/* couldve skipped spaces and got nothing.. */
while(!EmptyString(s)) while(!EmptyString(s))
{ {
/* ban with a leading ':' -- this will break the protocol */
if(*s == ':') if(*s == ':')
goto nextban; {
/* ban with a leading ':' -- this will break the protocol */
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Link %s dropped, invalid BMASK mask (%s)", source_p->name, s);
snprintf(squitreason, sizeof squitreason, "Invalid BMASK mask (%s)", s);
exit_client(client_p, client_p, client_p, squitreason);
return;
}
tlen = strlen(s); tlen = strlen(s);
@ -368,53 +377,83 @@ ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
parv[3][0], s, forward); parv[3][0], s, forward);
} }
if(add_id(fakesource_p, chptr, s, forward, banlist, mode_type)) mask = s;
if (extended) {
when = atol(strtok(NULL, " "));
who = strtok(NULL, " ");
if (who == NULL)
{ {
/* EBMASK params don't divide by 3, so we have an incomplete chunk */
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
"Link %s dropped, invalid EBMASK chunk", source_p->name);
snprintf(squitreason, sizeof squitreason, "Invalid EBMASK chunk");
exit_client(client_p, client_p, client_p, squitreason);
return;
}
arglen = sprintf(degrade_ptr, "%s ", mask);
degrade_ptr += arglen;
}
if((banptr = add_id(fakesource_p, chptr, mask, forward, banlist, mode_type)) != NULL)
{
banptr->when = when;
rb_free(banptr->who);
banptr->who = rb_strdup(who);
/* this new one wont fit.. */ /* this new one wont fit.. */
if(mlen + MAXMODEPARAMS + plen + tlen > BUFSIZE - 5 || if(mlen + MAXMODEPARAMS + plen + tlen > BUFSIZE - 5 ||
modecount >= MAXMODEPARAMS) modecount >= MAXMODEPARAMS)
{ {
*mbuf = '\0'; *output_ptr = '\0';
*(pbuf - 1) = '\0'; *(param_ptr - 1) = '\0';
sendto_channel_local(fakesource_p, mems, chptr, "%s %s", modebuf, parabuf); sendto_channel_local(fakesource_p, mems, chptr, "%s %s", output, parabuf);
mbuf = modebuf + mlen; output_ptr = output + mlen;
pbuf = parabuf; param_ptr = parabuf;
plen = modecount = 0; plen = modecount = 0;
} }
if (forward != NULL) if (forward != NULL)
forward[-1] = '$'; forward[-1] = '$';
*mbuf++ = parv[3][0]; *output_ptr++ = parv[3][0];
arglen = sprintf(pbuf, "%s ", s); arglen = sprintf(param_ptr, "%s ", mask);
pbuf += arglen; param_ptr += arglen;
plen += arglen; plen += arglen;
modecount++; modecount++;
} }
nextban: s = strtok(NULL, " ");
s = t;
if(s != NULL)
{
if((t = strchr(s, ' ')) != NULL)
{
*t++ = '\0';
while(*t == ' ')
t++;
}
}
} }
if(modecount) if(modecount)
{ {
*mbuf = '\0'; *output_ptr = '\0';
*(pbuf - 1) = '\0'; *(param_ptr - 1) = '\0';
sendto_channel_local(fakesource_p, mems, chptr, "%s %s", modebuf, parabuf); sendto_channel_local(fakesource_p, mems, chptr, "%s %s", output, parabuf);
} }
if (extended) {
*(degrade_ptr - 1) = '\0';
sendto_server(client_p, chptr, CAP_EBMASK | CAP_TS6 | needcap, NOCAPS, ":%s EBMASK %ld %s %s :%s",
source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
sendto_server(client_p, chptr, CAP_TS6 | needcap, CAP_EBMASK, ":%s BMASK %ld %s %s :%s",
source_p->id, (long) chptr->channelts, chptr->chname, parv[3], degrade);
}
else
sendto_server(client_p, chptr, CAP_TS6 | needcap, NOCAPS, ":%s BMASK %ld %s %s :%s", sendto_server(client_p, chptr, CAP_TS6 | needcap, NOCAPS, ":%s BMASK %ld %s %s :%s",
source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]); source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
} }
static void
ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
do_bmask(false, msgbuf_p, client_p, source_p, parc, parv);
}
static void
ms_ebmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
do_bmask(true, msgbuf_p, client_p, source_p, parc, parv);
}