summaryrefslogtreecommitdiff
path: root/doc/technical/ts3.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/technical/ts3.txt')
-rw-r--r--doc/technical/ts3.txt321
1 files changed, 321 insertions, 0 deletions
diff --git a/doc/technical/ts3.txt b/doc/technical/ts3.txt
new file mode 100644
index 0000000..e2f4927
--- /dev/null
+++ b/doc/technical/ts3.txt
@@ -0,0 +1,321 @@
+$Id$
+ Protocol changes for +TSora
+ ---------------------------
+
+Note:
+
+The protocols described here implement TimeStamps on IRC channels and
+nicks. The idea of IRC TimeStamps was started on Undernet, and first
+implemented by Run <carlo@runaway.xs4all.nl>. The protocols used here
+are not exactly the same as the ones used on Undernet; the nick-kill
+handling is very similar and must be credited to Run, while the
+"TimeStamped channel description" protocol is quite different.
+
+TSora servers keep track of which version of the TS protocol (if any)
+their neighboring servers are using, and take it into account when
+sending messages to them. This allows for seamless integration of TS
+servers into a non-TS net, and for upgrades of the protocol.
+
+Each server knows which is the lowest and the highest version of the
+TS protocol it can interact with; currently both of these are set to 1:
+
+#define TS_CURRENT 1 /* the highest TS ver we can do */
+#define TS_MIN 1 /* the lowest TS ver we can do */
+
+Timings and TS versions:
+========================
+
+. Keep a 'delta' value to be added to the result of all calls to time(),
+ initially 0.
+
+. Send a second argument to the PASS command, ending in the 'TS' string.
+
+. Send a
+
+ SVINFO <TS_CURRENT> <TS_MIN> <STANDALONE> :<UTC-TIME>
+
+ just after "SERVER", where <STANDALONE> is 1 if we're connected to
+ more TSora servers, and 0 if not, and <UTC-TIME> is our idea of the
+ current UTC time, fixed with the delta.
+
+. When we receive a "SVINFO <x> <y> <z> :<t>" line from a connecting
+ server, we ignore it if TS_CURRENT<y or x<TS_MIN, otherwise we
+ set a flag remembering that that server is TS-aware, remember the TS
+ version to use with it (min(TS_CURRENT, x)). Additionally, if this is
+ our first connected TS server, we set our delta to t-<OUR_UTC> if
+ z==0, and to (t-<OUR_UTC>)/2 if z!=0. The SVINFO data is kept around
+ until the server has effectively registered with SERVER, and used
+ *after* sending our own SVINFO to that server.
+
+Explanations:
+
+ Servers will always know which of their directly-linked servers can do
+ TS, and will use the TS protocol only with servers that do understand
+ it. This makes it possible to switch to full TS in just one
+ code-replacement step, without incompatibilities.
+
+ As long as not all servers are TS-aware, the net will be divided into
+ "zones" of linked TS-aware servers. Channel modes will be kept
+ synchronized at least within the zone in which the channel was
+ created, and nick collisions between servers in the same zone will
+ result in only one client being killed.
+
+ Time synchronization ensures that servers have the same idea of the
+ current time, and achieves this purpose as long as TS servers are
+ introduced one by one within the same 'zone'. The merging of two zones
+ cannot synchronize them completely, but it is to be expected that
+ within each zone the effective time will be very close to the real
+ time.
+
+ By sending TSINFO after SERVER rather than before, we avoid the extra
+ lag created by the identd check on the server. To be able to send
+ immediately a connect burst of either type (TS or not), we need to
+ know before that if the server does TS or not, so we send that
+ information with PASS as an extra argument. And to avoid being
+ incompatible with 2.9 servers, which check that this second argument
+ begins with "2.9", we check that it *ends* with "TS".
+
+ The current time is only used when setting a TS on a new channel or
+ nick, and once such a TS is set, it is never modified because of
+ synchronization, as it is much more important that the TS for a
+ channel or nick stays the same across all servers than that it is
+ accurate to the second.
+
+ Note that Undernet's 2.8.x servers have no time synchronization at
+ all, and have had no problems because of it - all of this is more to
+ catch the occasional server with a way-off clock than anything.
+
+NICK handling patches (anti-nick-collide + shorter connect burst):
+==================================================================
+
+. For each nick, store a TS value = the TS value received if any, or our
+ UTC+delta at the time we first heard of the nick. TS's are propagated
+ to TS-aware servers whenever sending a NICK command.
+
+. Nick changes reset the TS to the current time.
+
+. When sending a connect burst to another TS server, replace the
+ NICK/USER pair with only one NICK command containing the nick, the
+ hopcount, the TS, the umode, and all the USER information.
+
+ The format for a full NICK line is:
+ NICK <nick> <hops> <TS> <umode> <user> <host> <server> :<ircname>
+
+ The umode is a + followed by any applying usermodes.
+
+ The format for a nick-change NICK line is:
+ :<oldnick> NICK <newnick> :<TS>
+
+. When a NICK is received from a TS server, that conflicts with an
+ existing nick:
+ + if the userhosts differ or one is not known:
+ * if the timestamps are equal, kill ours and the old one if it
+ was a nick change
+ * if the incoming timestamp is older than ours, kill ours and
+ propagate the new one
+ * if the incoming timestamp is younger, ignore the line, but kill
+ the old nick if it was a nick change
+ + if the userhosts are the same:
+ * if the timestamps are equal, kill ours and the old one if it
+ was a nick change
+ * if the incoming timestamp is younger, kill ours and propagate
+ the new one
+ * if the incoming timestamp is older, ignore the line but kill
+ the old nick if it was a nick change
+
+. When a NICK is received from a non-TS server that conflicts with
+ an existing nick, kill both.
+
+. Do not send "Fake Prefix" kills in response to lines coming from TS
+ servers; the sanitization works anyway, and this allows the "newer
+ nick overruled" case to work.
+
+Explanations:
+
+ The modified nick-introduction syntax allows for a slightly shorter
+ connect-burst, and most importantly lets the server compare
+ user@host's when determining which nick to kill: if the user@host
+ is the same, then the older nick must be killed rather than the
+ newer.
+
+ When talking to a non-TS server, we need to behave exactly like one
+ because it expects us to. When talkign to a TS server, we don't kill
+ the nicks it's introducing, as we know it'll be smart enough to do it
+ itself when seeing our own introduced nick.
+
+ When we see a nick arriving from a non-TS server, it won't have a TS,
+ but it's safe enough to give it the current time rather than keeping
+ it 0; such TS's won't be the same all across the network (as long as
+ there is more than one TS zone), and when there's a collision, the TS
+ used will be the one in the zone the collision occurs in.
+
+ Also, it is important to note that by the time a server sees (and
+ chooses to ignore) a nick introduction, the introducing server has
+ also had the time to put umode changes for that nick on its queue, so
+ we must ignore them too... so we need to ignore fake-prefix lines
+ rather than sending kills for them. This is safe enough, as the rest
+ of the protocol ensures that they'll get killed anyway (and the
+ Undernet does it too, so it's been more than enough tested). Just for
+ an extra bit of compatibility, we still kill fake prefixes coming from
+ non-TS servers.
+
+ This part of the TS protocol is almost exactly the same as the
+ Undernet's .anc (anti-nick-collide) patches, except that Undernet
+ servers don't add usermodes to the NICK line.
+
+TimeStamped channel descriptions (avoiding hacked ops and desynchs):
+====================================================================
+
+. For each channel, keep a timestamp, set to the current time when the
+ channel is created by a client on the local server, or to the received
+ value if the channel has been propagated from a TS server, or to 0
+ otherwise. This value will have the semantics of "the time of creation
+ of the current ops on the channel", and 0 will mean that the channel
+ is in non-TS mode.
+
+ A new server protocol command is introduced, SJOIN, which introduces
+ a full channel description: a timestamp, all the modes (except bans),
+ and the list of channel members with their ops and voices. This
+ command will be used instead of JOIN and of (most) MODEs both in
+ connect bursts and when propagating channel creations among TS
+ servers. SJOIN will never be accepted from or sent to users.
+
+ The syntax for the command is:
+
+ SJOIN <TS> #<channel> <modes> :[@][+]<nick_1> ... [@][+]<nick_n>
+
+ The fields have the following meanings:
+
+ * <TS> is the timestamp for the channel
+
+ * <modes> is the list of global channel modes, starting with a +
+ and a letter for each of the active modes (spmntkil), followed
+ by an argument for +l if there is a limit, and an argument for
+ +k if there's a key (in the same order they were mentioned in
+ the string of letters).
+
+ A channel with no modes will have a "+" in that field.
+
+ A special value of "0" means that the server does not specify the
+ modes, and will be used when more than one SJOIN line is needed
+ to completely describe a channel, or when propagating a SJOIN
+ the modes of which were rejected.
+
+ * Each nick is preceded by a "@" if the user has ops, and a "+" if
+ the user has a voice. For mode +ov, both flags are used.
+
+ SJOINs will be propagated (when appropriate) to neighboring TS
+ servers, and converted to JOINs and MODEs for neighboring non-TS
+ servers.
+
+ To propagate channels for which not all users fit in one
+ SJOIN line, several SJOINs will be sent consecutively, only the first
+ one including actual information in the <mode> field.
+
+ An extra ad-hoc restriction is imposed on SJOIN messages, to simplify
+ processing: if a channel has ops, then the first <nick> of the first
+ SJOIN sent to propagate that channel must be one of the ops.
+
+ Servers will never attempt to reconstruct a SJOIN from JOIN/MODE
+ information being received at the moment from other servers.
+
+. For each user on a channel, keep an extra flag (like ops and voice)
+ that is set when the user has received channel ops from another
+ server (in a SJOIN channel description), which we rejected (ignored).
+ Mode changes (but NOT kicks) coming from a TS server and from someone
+ with this flag set will be ignored. The flag will be reset when the
+ user gets ops from another user or server.
+
+. On deops done by non-local users, coming from TS servers, on channels
+ with a non-zero TS, do not check that the user has ops but check that
+ their 'deopped' flag is not set. For kicks coming from a TS server, do
+ not check either. This will avoid desynchs, and 'bad' modechanges are
+ avoided anyway. Other mode changes will still only be taken into
+ account and propagated when done by users that are seen as having ops.
+
+. When a MODE change that ops someone is received from a server for a
+ channel, that channel's TS is set to 0, and the mode change is
+ propagated.
+
+. When a SJOIN is received for a channel, deal with it in this way:
+ * received-TS = 0:
+ + if we have ops or the SJOIN doesn't op anyone, SJOIN propagated
+ with our own TS.
+ + otherwise, TS set to 0 and SJOIN propagated with 0.
+ * received-TS > 0, own-TS = 0:
+ + if the SJOIN ops someone or we don't have ops, set our TS to the
+ received TS and propagate.
+ + otherwise, propagate with TS = 0.
+ * received-TS = own-TS: propagate.
+ * received-TS < own-TS:
+ + if the SJOIN ops someone, remove *all* modes (except bans) from
+ the channel and propagate these mode changes to all neighboring
+ non-TS servers, and copy the received TS and propagate the SJOIN.
+ + if the SJOIN does not op anyone and we have ops, propagate
+ with our own TS.
+ + otherwise, copy the received TS and propagate the SJOIN.
+ * received-TS > own-TS:
+ + if the SJOIN does not introduce any ops, process and propagate
+ with our own TS.
+ + if we have ops: for each person the mode change would op, set the
+ 'deopped' flag; process all the JOINs ignoring the '@' and '+'
+ flags; propagate without the flags and with our TS.
+ + if we don't have ops: set our TS to the received one, propagate
+ with the flags.
+
+Explanations:
+
+ This part of the protocol is the one that is most different (and
+ incompatible) with the Undernet's: we never timestamp MODE changes,
+ but instead we introduce the concept of time-stamped channel
+ descriptions. This way each server can determine, based on its state
+ and the received description, what the correct modes for a channel
+ are, and deop its own users if necessary. With this protocol, there is
+ *never* the need to reverse and bounce back a mode change. This is
+ both faster and more bandwith-effective.
+
+ The end goal is to have a protocol will eventually protect channels
+ against hacked ops, while minimizing the impact on a mixed-server net.
+ In order to do this, whenever there is a conflict between a TS server
+ and a non-TS one, the non-TS one's idea of the whole situation
+ prevails. This means that channels will only have a TS when they have
+ been created on a TS-aware server, and will lose it whenever a server
+ op comes from a non-TS server. Also, at most one 'zone' will have a TS
+ for any given channel at any given time, ensuring that there won't be
+ any deops when zones are merged. However, when TS zones are merged, if
+ the side that has a TS also has ops, then the TS is kept across the
+ whole new zone. Effective protection will only be ensured once all
+ servers run TS patches and channels have been re-created, as there is
+ no way servers can assign a TS to a channel they are not creating
+ (like they do with nicks) without having unwanted deops later.
+
+ The visible effects of this timestamped channel-description protocol
+ are that when a split rejoins, and one side has hacked ops, the other
+ side doesn't see any server mode changes (just like with Undernet's
+ TS), but the side that has hacked ops sees:
+
+ * first the first server on the other side deopping and devoicing
+ everyone, and fixing the +spmntkli modes
+ * then other users joining, and getting server ops and voices
+
+ The less obvious part of this protocol is its behavior in the case
+ that the younger side of a rejoin has servers that are lagged with
+ each other. In such a situation, a SJOIN that clears all modes and
+ sets the legitimate ones is being propagated from one server, and
+ lagged illegitimate mode changes and kicks are being propagated in the
+ opposite direction. In this case, a kick done by someone who is being
+ deopped by the SJOIN must be taken into account to keep the name list
+ in sync (and since it can only be kicking someone who also was on the
+ younger side), while a deop does not matter (and will be ignored by
+ the first server on the other side), and an opping *needs* to be
+ discareded to avoid hacked ops.
+
+ The main property of timestamped channel descriptions that makes them
+ a very stable protocol even with lag and splits, is that they leave a
+ server in the same final state, independently of the order in which
+ channel descriptions coming from different servers are received. Even
+ when SJOINs and MODEs for the same channel are being propagated in
+ different direction because of several splits rejoining, the final
+ state will be the same, independently of the exact order in which each
+ server received the SJOINs, and will be the same across all the
+ servers in the same zone.