From 8dcf73d0d63a5bad4380a96ed3ab6675ad880bba Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Sat, 18 Mar 2006 15:52:58 +0000 Subject: [PATCH] Avoid unwanted races for mode handling during burst processing. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1629 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 12 ++++++++++ ircd/channel.c | 60 +++++++++++++++++++++++++++++++++---------------- ircd/m_create.c | 47 +++++++++++++++++++++++++------------- ircd/m_mode.c | 10 +++++++-- 4 files changed, 93 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index 277698b..fbcc650 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-06-18 Michael Poole + + * ircd/channel.c (modebuf_flush_int): Fix typo about changing + oplevels. Send correct channel TS for modes to other servers. + (mode_parse): Accept timestamps on modes from users on other + servers. If the received timestamp is too large, handle that. + + * ircd/m_create.c (ms_create): Mention the CREATE-during-burst + case and handle it. + + * ircd/m_mode.c (ms_mode): Put back HACK(3) when oplevels are off. + 2006-03-14 Wouter Coekarts * ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field. diff --git a/ircd/channel.c b/ircd/channel.c index 99e5182..e79dba7 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -1805,7 +1805,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) strptr_i = &remstr_i; } - /* if we're changing oplevels we know the oplevel, pass it on */ + /* if we're changing oplevels and we know the oplevel, pass it on */ if (mbuf->mb_channel->mode.apass[0] && (MB_TYPE(mbuf, i) & MODE_CHANOP) && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL) @@ -1849,9 +1849,9 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) addbuf, remstr, addstr); } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) { /* - * If HACK2 was set, we're bouncing; we send the MODE back to the - * connection we got it from with the senses reversed and a TS of 0; - * origin is us + * If HACK2 was set, we're bouncing; we send the MODE back to + * the connection we got it from with the senses reversed and + * the proper TS; origin is us */ sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel, addbuf_i ? "-" : "", addbuf, @@ -1859,21 +1859,14 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) mbuf->mb_channel->creationtime); } else { /* - * We're propagating a normal MODE command to the rest of the network; - * we send the actual channel TS unless this is a HACK3 or a HACK4 + * We're propagating a normal (or HACK3 or HACK4) MODE command + * to the rest of the network. We send the actual channel TS. */ - if (IsServer(mbuf->mb_source) || IsMe(mbuf->mb_source)) - sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect, - "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel, - rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", - addbuf, remstr, addstr, - (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 : - mbuf->mb_channel->creationtime); - else - sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect, - "%H %s%s%s%s%s%s", mbuf->mb_channel, - rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", - addbuf, remstr, addstr); + sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect, + "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel, + rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", + addbuf, remstr, addstr, + mbuf->mb_channel->creationtime); } } @@ -3272,7 +3265,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, state.parc--; /* is it a TS? */ - if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) { + if (IsServer(state.cptr) && !state.parc && IsDigit(*modestr)) { time_t recv_ts; if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */ @@ -3282,6 +3275,35 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, if (recv_ts && recv_ts < state.chptr->creationtime) state.chptr->creationtime = recv_ts; /* respect earlier TS */ + else if (recv_ts > state.chptr->creationtime) { + struct Client *sserv; + + /* Check whether the originating server has fully processed + * the burst to it. */ + sserv = state.cptr; + if (!IsServer(sserv)) + sserv = cli_user(sserv)->server; + if (IsBurstOrBurstAck(sserv)) { + /* This is a legal but unusual case; the source server + * probably just has not processed the BURST for this + * channel. It SHOULD wipe out all its modes soon, so + * silently ignore the mode change rather than send a + * bounce that could desync modes from our side (that + * have already been sent). + */ + state.mbuf->mb_add = 0; + state.mbuf->mb_rem = 0; + state.mbuf->mb_count = 0; + return state.args_used; + } else { + /* Server is desynced; bounce the mode and deop the source + * to fix it. */ + state.mbuf->mb_dest &= ~MODEBUF_DEST_CHANNEL; + state.mbuf->mb_dest |= MODEBUF_DEST_BOUNCE | MODEBUF_DEST_HACK2; + if (!IsServer(state.cptr)) + state.mbuf->mb_dest |= MODEBUF_DEST_DEOP; + } + } break; /* break out of while loop */ } else if (state.flags & MODE_PARSE_STRICT || diff --git a/ircd/m_create.c b/ircd/m_create.c index e27e566..db21be8 100644 --- a/ircd/m_create.c +++ b/ircd/m_create.c @@ -172,7 +172,7 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) the fact that it was a zannel. The influence of this on a network that is completely 2.10.12.03 or higher is neglectable: Normally a server only sends a CREATE after first sending a DESTRUCT. Thus, - by receiving a CREATE for a zannel one of two things happened: + by receiving a CREATE for a zannel one of three things happened: 1. The DESTRUCT was sent during a net.break; this could mean that our zannel is at the verge of expiring too, it should have been destructed. It is correct to copy the newer TS now, all modes @@ -185,28 +185,45 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) already left within the time span of a message propagation. The channel will therefore be less than 48 hours old and no 'protection' is necessary. + 3. The source server sent the CREATE while linking, + before it got the BURST for our zannel. If this + happens, we should reset the channel back to the old + timestamp. This can be distinguished from case #1 by + checking IsBurstOrBurstAck(cli_user(sptr)->server). */ !(chptr->users == 0 && !chptr->mode.apass[0]))) { - modebuf_init(&mbuf, sptr, cptr, chptr, - (MODEBUF_DEST_SERVER | /* Send mode to server */ - MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */ - MODEBUF_DEST_BOUNCE)); /* And bounce the mode */ - - modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1); - - modebuf_flush(&mbuf); - - badop = 1; + if (!IsBurstOrBurstAck(cli_user(sptr)->server)) { + modebuf_init(&mbuf, sptr, cptr, chptr, + (MODEBUF_DEST_SERVER | /* Send mode to server */ + MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */ + MODEBUF_DEST_BOUNCE)); /* And bounce the mode */ + + modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1); + + modebuf_flush(&mbuf); + + badop = 1; + } else if (chanTS > chptr->creationtime + 4) { + /* If their handling of the BURST will lead to deopping the + * user, have the user join without getting ops (if the + * server's handling of the BURST keeps their ops, the channel + * will use our timestamp). + */ + badop = 1; + } + + if (badop) + joinbuf_join(&join, chptr, 0); } } else /* Channel doesn't exist: create it */ chptr = get_channel(sptr, name, CGT_CREATE); - if (!badop) /* Set/correct TS */ + if (!badop) { + /* Set (or correct) our copy of the TS */ chptr->creationtime = chanTS; - - joinbuf_join(badop ? &join : &create, chptr, - (badop ? 0 : CHFL_CHANOP)); + joinbuf_join(&create, chptr, CHFL_CHANOP); + } } joinbuf_flush(&join); /* flush out the joins and creates */ diff --git a/ircd/m_mode.c b/ircd/m_mode.c index c994569..ca366cc 100644 --- a/ircd/m_mode.c +++ b/ircd/m_mode.c @@ -86,6 +86,7 @@ #include "client.h" #include "hash.h" #include "ircd.h" +#include "ircd_features.h" #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" @@ -177,10 +178,15 @@ ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK4)); /* Send a HACK(4) message */ + else if (!feature_bool(FEAT_OPLEVELS)) + modebuf_init(&mbuf, sptr, cptr, chptr, + (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ + MODEBUF_DEST_SERVER | /* Send mode to servers */ + MODEBUF_DEST_HACK3)); /* Send a HACK(3) message */ else /* Servers need to be able to op people who join using the Apass - * or upass, as well as people joining a zannel, therefore we no - * longer generate HACK3. */ + * or upass, as well as people joining a zannel, therefore we do + * not generate HACK3 when oplevels are on. */ modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ -- 2.20.1