[svn] Port over ratbox 2.2 r23507, r23624, r23626 (jilles/anfl):

Change TS6 JOIN processing
- don't send out simple modes in TS6 JOIN and TS5 SJOIN when
  a local user joins an existing channel
- don't send out simple modes in TS6 JOIN and TS5 SJOIN when
  propagating a TS6 JOIN
- don't interpret simple modes in an incoming TS6 JOIN

This is to avoid desyncs when certain mode changes (e.g. -im)
cross with joins. A downside is that simple modes will be
more desynched when a JOIN creates a channel or lowers TS,
but that's less important.

Update the TS6 specification to include this, and clarify
that TMODE can come from a server and that MODE must be
translated into TMODE from other servers too.
This commit is contained in:
jilles 2007-02-19 16:34:28 -08:00
parent 9b6ff0c8f9
commit bee3b6716c
4 changed files with 102 additions and 171 deletions

View file

@ -1,3 +1,12 @@
jilles 2007/02/11 16:54:43 UTC (20070211-3209)
Log:
Make -logfile work again.
Changes: Modified:
+2 -2 trunk/src/s_log.c (File Modified)
nenolod 2007/02/09 22:18:23 UTC (20070209-3205) nenolod 2007/02/09 22:18:23 UTC (20070209-3205)
Log: Log:
- fix off-by-one memory overflow error. - fix off-by-one memory overflow error.

View file

@ -1,11 +1,35 @@
$Id: ts6.txt 6 2005-09-10 01:02:21Z nenolod $ $Id: ts6.txt 3211 2007-02-20 00:34:28Z jilles $
TS6 Proposal (v7) TS6 Proposal (v8)
Written by Lee H <lee@leeh.co.uk> Written by Lee H <lee@leeh.co.uk>
Ideas borrowed heavily from ircnet (Beeth, jv, Q) Ideas borrowed heavily from ircnet (Beeth, jv, Q)
Introduction - Changes between v7 and v8 -
------------ -----------------------------
In the v7 specification, the JOIN command included the channel modes of a
channel, and acted on them following TS rules. In the v8 specification,
JOIN will never send modes.
Desyncs can occur both when they are sent and when they are not. If they
are sent, then you can have a situation where a user on one side of the
network issues "MODE #channel -l", and a user on another side of the network
issues "JOIN #channel" whilst the +l still exists. As the JOIN string sent
server<->server includes the full modes at the time of the user joining,
this will propagate the +l, but there is a -l crossing in the other
direction. Desync will occur beyond where they intersect.
If the modes are not sent, then a lower TS JOIN command, or a JOIN command
that creates a channel will cause a desync.
It is judged that the desync with sending the modes is worse than the desync
by not sending them, as such the v8 specification dictates modes are not
sent with a JOIN command server<->server.
The v8 specification also clarifies that servers may issue TMODE.
- Introduction -
----------------
This document aims to fix some of the flaws that are still present in the This document aims to fix some of the flaws that are still present in the
current TS system. current TS system.
@ -28,8 +52,8 @@ issue a mode during a netburst and the mode will be set on the server
we are bursting to. we are bursting to.
Definitions - Definitions -
----------- ---------------
Throughout this document, the following terms are used: Throughout this document, the following terms are used:
@ -43,8 +67,8 @@ UID - An ID concateneted to a SID. This forms the clients UID.
TS6 - The TS version 6. TS6 - The TS version 6.
Support - Support -
------- -----------
Support for this document is given by the TS version 6. Support for this document is given by the TS version 6.
@ -60,8 +84,8 @@ http://www.leeh.co.uk/ircd/encap.txt
The TS6 protocol does not supports masked entities. The TS6 protocol does not supports masked entities.
Nick TS rules - Nick TS rules -
------------- -----------------
A server receiving a command that requires nick TS rules must check for a A server receiving a command that requires nick TS rules must check for a
collision between an existing user, and the nick in the received message. collision between an existing user, and the nick in the received message.
@ -81,8 +105,8 @@ clients user@host are different it will collide the new user and drop the
message. message.
Nick TS collisions - Nick TS collisions -
------------------ ----------------------
If both users are to be collided, we must issue a KILL for the existing If both users are to be collided, we must issue a KILL for the existing
user to all servers. If the new user has a UID then we must also issue a user to all servers. If the new user has a UID then we must also issue a
@ -98,8 +122,8 @@ If only the new user is being collided, we must issue a KILL for the new user
back to the server sending us data if the new user has a UID. back to the server sending us data if the new user has a UID.
Channel TS rules - Channel TS rules -
---------------- --------------------
A server receiving a command that requires normal channel TS rules must A server receiving a command that requires normal channel TS rules must
apply the following rules to the command. apply the following rules to the command.
@ -125,8 +149,8 @@ losing their op (+o) status who do not have a UID as 'deopped'. A server must
ignore any "MODE" commands from a user marked as 'deopped'. ignore any "MODE" commands from a user marked as 'deopped'.
Simple channel TS rules - Simple channel TS rules -
----------------------- ---------------------------
A server receiving a command that requires simple channel TS rules must A server receiving a command that requires simple channel TS rules must
apply the following rules to the command. apply the following rules to the command.
@ -139,10 +163,10 @@ Simple channel TS rules do not affect current modes in the channel except
for the modes we are accepting. for the modes we are accepting.
The following commands are defined here as the TS6 protocol - The following commands are defined here as the TS6 protocol -
----------------------------------------------------------- ---------------------------------------------------------------
PASS: - PASS -
PASS <PASSWORD> TS <TS_CURRENT> :<SID> PASS <PASSWORD> TS <TS_CURRENT> :<SID>
This command is used for password verification with the server we are This command is used for password verification with the server we are
@ -156,7 +180,7 @@ The <PASSWORD> field is the password we have stored for this server,
<TS_CURRENT> is our current TS version. If this field is not present then <TS_CURRENT> is our current TS version. If this field is not present then
the server does not support TS6. <SID> is the SID of the server. the server does not support TS6. <SID> is the SID of the server.
UID: - UID -
:<SID> UID <NICK> <HOPS> <TS> +<UMODE> <USERNAME> <HOSTNAME> <IP> <UID> :<GECOS> :<SID> UID <NICK> <HOPS> <TS> +<UMODE> <USERNAME> <HOSTNAME> <IP> <UID> :<GECOS>
This command is used for introducing clients to the network. This command is used for introducing clients to the network.
@ -176,7 +200,7 @@ clients UID. The <GECOS> field is the clients gecos.
A server receiving a UID command must apply nick TS rules to the nick. A server receiving a UID command must apply nick TS rules to the nick.
SID: - SID -
:<SID> SID <SERVERNAME> <HOPS> <SID> :<GECOS> :<SID> SID <SERVERNAME> <HOPS> <SID> :<GECOS>
This command is used for introducing servers to the network. This command is used for introducing servers to the network.
@ -196,7 +220,7 @@ connected server through which the command was received.
Client and servers which do not have a UID/SID must be introduced by old Client and servers which do not have a UID/SID must be introduced by old
methods. methods.
SJOIN: - SJOIN -
:<SID> SJOIN <TS> <CHANNAME> +<CHANMODES> :<UIDS> :<SID> SJOIN <TS> <CHANNAME> +<CHANMODES> :<UIDS>
This command is used for introducing users to channels. This command is used for introducing users to channels.
@ -216,22 +240,27 @@ to introduce a single user to an existing channel. It must instead
use the "JOIN" command defined in this specification. A TS6 server must use the "JOIN" command defined in this specification. A TS6 server must
still use SJOIN for creating channels. still use SJOIN for creating channels.
JOIN: - JOIN -
:<UID> JOIN <TS> <CHANNAME> +<CHANMODES> :<UID> JOIN <TS> <CHANNAME> +
This command is used for introducing one user unopped to an existing channel. This command is used for introducing one user unopped to an existing channel.
The <UID> field is the UID of the client joining the channel. The The <UID> field is the UID of the client joining the channel. The
<TS> field is the channels current TS, <CHANNAME> is the channels <TS> field is the channels current TS, <CHANNAME> is the channels
current name, <CHANMODES> are the channels current modes. current name.
A server receiving a JOIN must apply normal channel TS rules to the JOIN. A server receiving a JOIN must apply normal channel TS rules to the JOIN.
It should be noted that whilst JOIN would not normally create a No channel modes are sent with the JOIN command. In previous versions of
channel, during specific race conditions it can. This can create this specification, the "+" parameter contained the channels current modes.
a ban desync that this specification does not rectify. A server following this version of the specification must not interpret this
argument and must not propagate any value other than "+" for this parameter.
BMASK: It should be noted that whilst JOIN would not normally create a
channel or lower the timestamp, during specific conditions it can. This
can create a desync that this specification does not rectify.
- BMASK -
:<SID> BMASK <TS> <CHANNAME> <TYPE> :<MASKS> :<SID> BMASK <TS> <CHANNAME> <TYPE> :<MASKS>
This command is used for bursting channel bans to a network. This command is used for bursting channel bans to a network.
@ -253,17 +282,18 @@ It should be noted however, that a BMASK with a lower TS should
not be possible without a desync, due to it being sent after not be possible without a desync, due to it being sent after
SJOIN. SJOIN.
TMODE: - TMODE -
:<UID> TMODE <TS> <CHANNAME> <MODESTRING> :<SID|UID> TMODE <TS> <CHANNAME> <MODESTRING>
This command is used for clients issuing modes on a channel. This command is used for clients issuing modes on a channel.
<UID> is the UID of the client setting the mode. <TS> is the <SID|UID> is either the UID of the client setting the mode, or the SID of
current TS of the channel, <CHANNAME> is the channels name. the server setting the mode. <TS> is the current TS of the channel,
<MODESTRING> is the raw mode the client is setting. <CHANNAME> is the channels name. <MODESTRING> is the raw mode the client is
setting.
A server receiving a TMODE must apply simple channel TS rules to the TMODE. A server receiving a TMODE must apply simple channel TS rules to the TMODE.
A TS6 server must translate MODEs issued by a local client into TMODE A TS6 server must translate MODEs issued by a local client, or received from
to send to other TS6 capable servers. a server into TMODE to send to other TS6 capable servers.

View file

@ -1 +1 @@
#define SERNO "20070209-3205" #define SERNO "20070211-3209"

View file

@ -21,7 +21,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA * USA
* *
* $Id: m_join.c 3173 2007-01-31 23:57:18Z jilles $ * $Id: m_join.c 3211 2007-02-20 00:34:28Z jilles $
*/ */
#include "stdinc.h" #include "stdinc.h"
@ -62,7 +62,7 @@ mapi_hlist_av1 join_hlist[] = {
{ NULL, NULL }, { NULL, NULL },
}; };
DECLARE_MODULE_AV1(join, NULL, NULL, join_clist, join_hlist, NULL, "$Revision: 3173 $"); DECLARE_MODULE_AV1(join, NULL, NULL, join_clist, join_hlist, NULL, "$Revision: 3211 $");
static void do_join_0(struct Client *client_p, struct Client *source_p); static void do_join_0(struct Client *client_p, struct Client *source_p);
static int check_channel_name_loc(struct Client *source_p, const char *name); static int check_channel_name_loc(struct Client *source_p, const char *name);
@ -342,17 +342,15 @@ m_join(struct Client *client_p, struct Client *source_p, int parc, const char *p
} }
else else
{ {
const char *modes = channel_modes(chptr, &me);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS, sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s JOIN %ld %s %s", ":%s JOIN %ld %s +",
use_id(source_p), (long) chptr->channelts, use_id(source_p), (long) chptr->channelts,
chptr->chname, modes); chptr->chname);
sendto_server(client_p, chptr, NOCAPS, CAP_TS6, sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
":%s SJOIN %ld %s %s :%s", ":%s SJOIN %ld %s + :%s",
me.name, (long) chptr->channelts, me.name, (long) chptr->channelts,
chptr->chname, modes, source_p->name); chptr->chname, source_p->name);
} }
del_invite(chptr, source_p); del_invite(chptr, source_p);
@ -396,13 +394,10 @@ static int
ms_join(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) ms_join(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{ {
struct Channel *chptr; struct Channel *chptr;
static struct Mode mode, *oldmode; static struct Mode mode;
const char *s;
const char *modes;
time_t oldts; time_t oldts;
time_t newts; time_t newts;
int isnew; int isnew;
int args = 0;
int keep_our_modes = YES; int keep_our_modes = YES;
int keep_new_modes = YES; int keep_new_modes = YES;
dlink_node *ptr, *next_ptr; dlink_node *ptr, *next_ptr;
@ -428,89 +423,11 @@ ms_join(struct Client *client_p, struct Client *source_p, int parc, const char *
mode.key[0] = mode.forward[0] = '\0'; mode.key[0] = mode.forward[0] = '\0';
mode.mode = mode.limit = mode.join_num = mode.join_time = 0; mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
s = parv[3];
while(*s)
{
switch (*(s++))
{
case 'i':
mode.mode |= MODE_INVITEONLY;
break;
case 'n':
mode.mode |= MODE_NOPRIVMSGS;
break;
case 'p':
mode.mode |= MODE_PRIVATE;
break;
case 's':
mode.mode |= MODE_SECRET;
break;
case 'm':
mode.mode |= MODE_MODERATED;
break;
case 't':
mode.mode |= MODE_TOPICLIMIT;
break;
case 'r':
mode.mode |= MODE_REGONLY;
break;
case 'L':
mode.mode |= MODE_EXLIMIT;
break;
case 'P':
mode.mode |= MODE_PERMANENT;
break;
case 'c':
mode.mode |= MODE_NOCOLOR;
break;
case 'g':
mode.mode |= MODE_FREEINVITE;
break;
case 'z':
mode.mode |= MODE_OPMODERATE;
break;
case 'F':
mode.mode |= MODE_FREETARGET;
break;
case 'Q':
mode.mode |= MODE_DISFORWARD;
break;
case 'f':
if(parc < 5 + args)
return 0;
strlcpy(mode.forward, parv[4 + args], sizeof(mode.forward));
args++;
break;
case 'j':
/* sent a +j without an arg. */
if(parc < 5 + args)
return 0;
sscanf(parv[4 + args], "%d:%d", &mode.join_num, &mode.join_time);
args++;
break;
case 'k':
/* sent a +k without a key, eek. */
if(parc < 5 + args)
return 0;
strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
args++;
break;
case 'l':
/* sent a +l without a limit. */
if(parc < 5 + args)
return 0;
mode.limit = atoi(parv[4 + args]);
args++;
break;
}
}
if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL) if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
return 0; return 0;
newts = atol(parv[1]); newts = atol(parv[1]);
oldts = chptr->channelts; oldts = chptr->channelts;
oldmode = &chptr->mode;
#ifdef IGNORE_BOGUS_TS #ifdef IGNORE_BOGUS_TS
if(newts < 800000000) if(newts < 800000000)
@ -547,54 +464,29 @@ ms_join(struct Client *client_p, struct Client *source_p, int parc, const char *
else else
keep_new_modes = NO; keep_new_modes = NO;
if(!keep_new_modes)
mode = *oldmode;
else if(keep_our_modes)
{
mode.mode |= oldmode->mode;
if(oldmode->limit > mode.limit)
mode.limit = oldmode->limit;
if(strcmp(mode.key, oldmode->key) < 0)
strcpy(mode.key, oldmode->key);
if(oldmode->join_num > mode.join_num ||
(oldmode->join_num == mode.join_num &&
oldmode->join_time > mode.join_time))
{
mode.join_num = oldmode->join_num;
mode.join_time = oldmode->join_time;
}
if(irccmp(mode.forward, oldmode->forward) < 0)
strcpy(mode.forward, oldmode->forward);
}
else
{
/* If setting -j, clear join throttle state -- jilles */
if (!mode.join_num)
chptr->join_count = chptr->join_delta = 0;
}
set_final_mode(&mode, oldmode);
chptr->mode = mode;
/* Lost the TS, other side wins, so remove modes on this side */ /* Lost the TS, other side wins, so remove modes on this side */
if(!keep_our_modes) if(!keep_our_modes)
{ {
set_final_mode(&mode, &chptr->mode);
chptr->mode = mode;
remove_our_modes(chptr, source_p); remove_our_modes(chptr, source_p);
DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head) DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
{ {
del_invite(chptr, ptr->data); del_invite(chptr, ptr->data);
} }
/* If setting -j, clear join throttle state -- jilles */
chptr->join_count = chptr->join_delta = 0;
sendto_channel_local(ALL_MEMBERS, chptr, sendto_channel_local(ALL_MEMBERS, chptr,
":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld", ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
me.name, chptr->chname, chptr->chname, me.name, chptr->chname, chptr->chname,
(long) oldts, (long) newts); (long) oldts, (long) newts);
}
if(*modebuf != '\0') if(*modebuf != '\0')
sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s", sendto_channel_local(ALL_MEMBERS, chptr,
source_p->user->server, chptr->chname, modebuf, parabuf); ":%s MODE %s %s %s",
source_p->servptr->name,
chptr->chname, modebuf, parabuf);
*modebuf = *parabuf = '\0'; *modebuf = *parabuf = '\0';
}
if(!IsMember(source_p, chptr)) if(!IsMember(source_p, chptr))
{ {
@ -611,14 +503,14 @@ ms_join(struct Client *client_p, struct Client *source_p, int parc, const char *
source_p->host, chptr->chname); source_p->host, chptr->chname);
} }
modes = channel_modes(chptr, client_p);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS, sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s JOIN %ld %s %s", ":%s JOIN %ld %s +",
source_p->id, (long) chptr->channelts, chptr->chname, modes); source_p->id, (long) chptr->channelts, chptr->chname);
sendto_server(client_p, chptr, NOCAPS, CAP_TS6, sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
":%s SJOIN %ld %s %s :%s", ":%s SJOIN %ld %s %s :%s",
source_p->user->server, (long) chptr->channelts, source_p->user->server, (long) chptr->channelts,
chptr->chname, modes, source_p->name); chptr->chname, keep_new_modes ? "+" : "0",
source_p->name);
return 0; return 0;
} }