Avoid unwanted races for mode handling during burst processing.
authorMichael Poole <mdpoole@troilus.org>
Sat, 18 Mar 2006 15:52:58 +0000 (15:52 +0000)
committerMichael Poole <mdpoole@troilus.org>
Sat, 18 Mar 2006 15:52:58 +0000 (15:52 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1629 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
ircd/channel.c
ircd/m_create.c
ircd/m_mode.c

index 277698ba2170aa4b0d1309cb2a878d06bb823472..fbcc65089c2f9553626a5cbb082ba05360e28334 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2006-06-18  Michael Poole <mdpoole@troilus.org>
+
+       * 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 <wouter@coekaerts.be>
 
        * ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field.
index 99e5182e6df59427cf825313573f17bb60915c23..e79dba7641d6d17486354574b903783d5e3c7c9c 100644 (file)
@@ -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 ||
index e27e56649fda939dd8fa0333a8b3d2ee49fa43f1..db21be8d00de8f4b07b33ee2a28dcd88f773d9ca 100644 (file)
@@ -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 */
index c994569e878c5d7897c0dbb16bfc3f1ddf3fa71c..ca366ccd65bf243b430c84e6174f1016fac6af48 100644 (file)
@@ -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 */