serv1 will receive the first RSFNC, changing 001TARGET's nick to Guest12345. However, if it doesn't manage to do that and send a NICK to serv2 before serv2 receives the second RSFNC, serv2 will change 002TARGET's nick to foobar while still seeing 001TARGET's nick as foobar. The RSFNC spec requires that in this case 001TARGET is killed.
The kill could be avoided by issuing a SAVE, or by saving the first target in the first place instead of RSFNC-ing them. There is another solution, however: instead of requesting a nick change, have services unilaterally propagate a nick change. As commands from any given server cannot be reordered, the race condition is avoided.
UFNC
Our addition is as follows:
UFNC targetUID newnick nickTS
UFNC should only be issued by a services server. However, if attempts to enforce this are implemented, they must account for the fact that the nick change has already propagated; SAVE, SQUIT or KILL would be okay, while just ignoring the UFNC would not.
UFNC may not be issued for a UID (saved) nick.
UFNC must be silently ignored if nickTS does not match the target's TS. Otherwise, a server receiving a UFNC changes the target's nick to newnick, leaving its TS unchanged. It is propagated as a UFNC to servers that support it, or as a NICK to servers that do not.
If newnick already exists, its existing owner is killed, regardless of their TS, as with RSFNC.
We introduce a new server capability, also named UFNC, representing the ability of a server to process and propagate UFNC commands. Servers issuing UFNC must ensure their entire path to the vicitm's server has UFNC support. Servers receiving a UFNC message may enforce this.
Desync resistance
UFNC is not designed to handle the case where two different U-lined servers send conflicting UFNC messages.
In other cases, we believe UFNC cannot lead to nick desyncs:
Normal nick changes, including those generated by RSFNC, are either case changes or are guaranteed to change the nickTS, no matter how fast they are sent.
For regular nick changes which change the TS, a NICK racing with a UFNC will override the UFNC it arrives second, and invalidate the UFNC if it arrives first.
A case change NICK racing with a UFNC will be ignored if it arrives second (requiring a small modification to the NICK logic), and overridden if it arrives first.
Initial SAVEs change the TS, so a SAVE racing with a UFNC will win everywhere by the same logic as for a regular NICK.
A second SAVE does not change the TS, so a second SAVE racing with a UFNC could desync; it is therefore prohibited to send a UFNC for a saved nick.
When a UFNC is propagated as a NICK, the downgrade to NICK is performed by a server on the path between the UFNC originator and the owner of the nick. Therefore, from the point of view of a server without UFNC support, all nick changes for a given target pass through the downgrading server. If UFNC without downgrade is safe from desyncs, the downgrading server must have a consistent view of the target's nick, and since nick changes for the target can only come from the downgrading server, the non-UFNC server must have the same consistent view.
I'll copy the documentation in the PR below. If this is the first you've heard of this proposal, read that first.
This is a work in progress and should not be merged yet; I'm hoping that you, dear reader, will pick through it and look for cases I haven't covered.
Known issues:
UFNC: FNC as a real nick change
Motivation
seven, like charybdis, uses the RSFNC mechanism to enable services to change user nicknames. RSFNC looks like this:
and doesn't do anything by itself: it just asks victim's server to perform the equivalent of a /nick.
This causes a race condition when RSFNCs depend on each other. Starting with 001TARGET on the nick 'foobar', consider a typical services REGAIN:
serv1 will receive the first RSFNC, changing 001TARGET's nick to Guest12345. However, if it doesn't manage to do that and send a NICK to serv2 before serv2 receives the second RSFNC, serv2 will change 002TARGET's nick to foobar while still seeing 001TARGET's nick as foobar. The RSFNC spec requires that in this case 001TARGET is killed.
The kill could be avoided by issuing a SAVE, or by saving the first target in the first place instead of RSFNC-ing them. There is another solution, however: instead of requesting a nick change, have services unilaterally propagate a nick change. As commands from any given server cannot be reordered, the race condition is avoided.
UFNC
Our addition is as follows:
UFNC should only be issued by a services server. However, if attempts to enforce this are implemented, they must account for the fact that the nick change has already propagated; SAVE, SQUIT or KILL would be okay, while just ignoring the UFNC would not.
UFNC may not be issued for a UID (saved) nick.
UFNC must be silently ignored if nickTS does not match the target's TS. Otherwise, a server receiving a UFNC changes the target's nick to newnick, leaving its TS unchanged. It is propagated as a UFNC to servers that support it, or as a NICK to servers that do not.
If newnick already exists, its existing owner is killed, regardless of their TS, as with RSFNC.
We introduce a new server capability, also named UFNC, representing the ability of a server to process and propagate UFNC commands. Servers issuing UFNC must ensure their entire path to the vicitm's server has UFNC support. Servers receiving a UFNC message may enforce this.
Desync resistance
UFNC is not designed to handle the case where two different U-lined servers send conflicting UFNC messages.
In other cases, we believe UFNC cannot lead to nick desyncs:
Normal nick changes, including those generated by RSFNC, are either case changes or are guaranteed to change the nickTS, no matter how fast they are sent.
For regular nick changes which change the TS, a NICK racing with a UFNC will override the UFNC it arrives second, and invalidate the UFNC if it arrives first.
A case change NICK racing with a UFNC will be ignored if it arrives second (requiring a small modification to the NICK logic), and overridden if it arrives first.
Initial SAVEs change the TS, so a SAVE racing with a UFNC will win everywhere by the same logic as for a regular NICK.
A second SAVE does not change the TS, so a second SAVE racing with a UFNC could desync; it is therefore prohibited to send a UFNC for a saved nick.
When a UFNC is propagated as a NICK, the downgrade to NICK is performed by a server on the path between the UFNC originator and the owner of the nick. Therefore, from the point of view of a server without UFNC support, all nick changes for a given target pass through the downgrading server. If UFNC without downgrade is safe from desyncs, the downgrading server must have a consistent view of the target's nick, and since nick changes for the target can only come from the downgrading server, the non-UFNC server must have the same consistent view.