# Unreal 3.2 Protocol Documentation

### Last update: 29 November 2006

# Table of Contents

1 Introduction

2 Server Negotiation

> 2.1 PASS - Connection Password

> 2.2 PROTOCTL - Server Protocol Negotiation

> 2.3 SERVER - Server Negotiation

> 2.4 EOS - End Of Synch

> 2.5 NETINFO - Network Information

3 User Operations

> 3.1 NICK - User Introduction and Nick Change

> > 3.1.1 Nick Collisions

> 3.2 MODE, UMODE2 - User Mode Change

> 3.3 QUIT - User Disconnect

> 3.4 KILL - Force Disconnect

> 3.5 SETHOST/CHGHOST - Change virtual host

> 3.6 SETIDENT/CHGIDENT - Change a user's username

> 3.7 SETNAME/CHGNAME - Change a user's realname

> 3.8 WHOIS - User Information

4 Server Operations

> 4.1 SERVER - Server Introduction

> 4.2 SQUIT - Server Removal

> 4.3 SDESC - Server Description

> 4.4 PING - Live Connection Query

> 4.5 PONG - Live Connection Reply

> 4.6 STATS - Server Stats

5 Channel Operations

> 5.1 SJOIN - Channel Burst

> 5.2 JOIN - Channel Join

> 5.3 PART - Channel Part

> 5.4 KICK - Channel Kick

> 5.5 MODE - Channel Mode

> 5.6 INVITE - Invite a user to a channel

> 5.7 SAJOIN - Channel Force Join

> 5.8 SAPART - Channel Force Part

> 5.9 SAMODE - Channel Force Mode

> 5.10 TOPIC - Chanel Topic

6 Services Commands

> 6.1 SVSKILL - Force Disconnect by Service

> 6.2 SVSMODE, SVS2MODE - Force User Mode Change

> 6.3 SVSSNO, SVS2SNO - Forced SNomask Change

> 6.4 SVSNICK - Forced Nick Change

> 6.5 SVSJOIN - Forced Join

> 6.6 SVSPART - Forced Part

> 6.7 SVSO - Oper Permissions

> 6.8 SVSNOOP - Oper Lockdown

> 6.9 SVSNLINE - RealName Ban

> 6.10 SVSFLINE - File Ban

7 Messaging

> 7.1 PRIVMSG, NOTICE - Simple Message Transmission

> 7.2 SENDUMODE, SMO - Usermode-based Delivery

> 7.3 SENDSNO - SNomask-based Delivery

> 7.4 CHATOPS - IRCop Chat

> 7.5 WALLOPS - Wallop Chat

> 7.6 GLOBOPS - FailOp Chat

> 7.7 ADCHAT - Admin Chat

> 7.8 NACHAT - NetAdmin Chat

8 Ban Control

> 8.1 TKL - Master Ban Control

> > 8.1.1 GLINE - Network-wide user@host ban

> > 8.1.2 GZLINE - Network-wide IP ban

> > 8.1.3 SQLINE, UNSQLINE - Network-wide Nickname ban

> > 8.1.4 SPAMFILTER - Message Spam Filtration System

9 Base64 Tables

> 9.1 Table for NICKIP.

# 1 Introduction

This document describes the UnrealIRCd server-to-server protocol.

## A word about clocks.

Unreal is very time-dependant. Users and channels, for example, are timestamped, and if server clocks are not synchronized properly, things can go very wrong very fast. See http://vulnscan.org/UnrealIrcd/faq/#67 for more information on this. Note that there is a slight difference between server time and what is actually reported by the UNIX date command or by the C time() function. Unreal can apply an offset to the real time to create the server time, allowing servers to be virtually synchronized when synchronizing the real clocks is not possible (such as on shell servers). I should make it quite clear that GMT time is used for everything. To be specific, timestamps in unreal are 32-bit integer values (actually, however many bits the time_t type is, which is 32 on 32-bit systems such as x86). This integer value is the number of seconds that have elapsed since Midnight January 1, 1970 GMT (can be referred to as Epoch time in the UNIX world). This means that timezones are no problem, nor is daylight savings time (or whatever your country of choice calls it).

# 2 Server Negotiation

The first step to establish a server-to-server communication is to negotiate the connection as a server. Negotiation is done using standard IRC commands - no PROTOCTL options are in force until the link is established. The first step is to open a TCP/IP connection to the target server. The target port must be one described by a listen {} block in the remote server's configuration, and that listen block must not have the clientsonly option. After the connection is open, you will be treated as any other connection and be greeted with the "Looking up your hostname..." and "Checking identd..." notices as you would for a client. As these are NOTICE messages and your session as a server isn't established, they should simply be ignored. Use the commands below to introduce a server connection.

## 2.1 PASS - Connection Password

Syntax: `PASS :link password`

The PASS command is used to transmit the password required for a server link. It must match the password specified in the remote server's link::password-receive (which can be crypted), otherwise the link will be rejected. This should be the first message sent.

## 2.2 PROTOCTL - Server Protocol Negotiation

Syntax: `PROTOCTL protocol options`

The PROTOCTL command sets several protocol options. The tokens supported are listed below.

- NOQUIT : When a netsplit occurs, only send a SQUIT message for each server lost. This server will assume that clients on these servers were also lost and will send the appropriate QUIT messages to local clients and to any non-NOQUIT servers.
- TOKEN : Use tokenized commands. Tokens are case-sensitive, shortened versions of command names. Tokens will be usually one or two characters.
- NICKv2 : Use extended NICK message for introducing users. See the NICK command for information about this.
- VHP : When introducing a user, send his cloaked host as if it were a vhost. Usually used for services to avoid having duplicate code.
- SJOIN : Supports SJOIN version 1 which is no longer in use. Use with SJ3.
- SJOIN2 : Supports SJOIN version 2 which is no longer in use. Use with SJ3.
- UMODE2 : Supports the UMODE2 command, which is a shortened version of MODE for usermode changes.
- VL : Supports V:Line information. Extends the SERVER message to include version information used in deny version{} blocks. Note that this is assumed - unreal will always send its own version information.
- SJ3 : Supports SJOIN version 3.
- NS : Supports server numerics which provides a shorthand for server names. In any circumstance where a :server.name is permitted (the server is the message's real source), @servernumeric may be used instead. In addition, the server.name parameter in the NICK message may be simply the server's numeric. Requires VL support.
- TKLEXT : Supports exntended TKL messages for spamfilter support.
- NICKIP : Adds an IP parameter to the NICK message, which is the base64 encoding of the user's ip address (in network byte order). Requires NICKv2.
- NICKCHARS : Indicates the set of enabled nickchar options (see the regular documention for info about this).
- CHANMODES : (Not required to be sent) This is the same as the CHANMODES value in the 005 for client connections. Useful for autodetecting things like what modes are valid for ChanServ MLOCK, for example.
- CLK : Supports an extra field in NICK for sending the cloaked host (not vhost).
- ESVID : Supports arbitrary values instead of just numeric timestamps for the services identifier field.

The syntax examples here follow the conventions for TOKEN and also NS in cases of server-only messages.

## 2.3 SERVER - Server Negotiation

Note: This message is also used for introducing additional servers, the format of this message in those cases is described later.

Syntax (normal): `SERVER server.name 1 :server description`

Syntax (with VL): `SERVER server.name 1 :Uprotocolversion-protocolflags server description`

Syntax (with VL and NS): `SERVER server.name 1 :Uprotocolversion-protocolflags-servernumeric server description`

The literal 1 in the parameter list is the hopcount parameter. Since you are a direct link, your own hopcount will be 1.

The server.name is the same as that in the remote server's link:: block. When received from unreal servers, this will be the value of that server's me::name. The protocol version is the numeric protocol version (2306 for example), and the protocol flags are the server's compilation flags (described below). These two fields are checked against the deny version {} blocks in the remote server's configuration. A value of 0 for either field prevents deny version{} checking for that field. The server description can be anything. When received from unreal servers, it'll be the value of me::description.

The following version numbers have been used previously:

- 2311 - Unreal 3.2.10
- 2310 - Unreal 3.2.9
- 2309 - Unreal 3.2.6, 3.2.7, 3.2.8
- 2308 - Unreal 3.2.5
- 2307 - Unreal 3.2.4
- 2306 - Unreal 3.2.3
- 2305 - Unreal 3.2.2
- 2304 - Unreal 3.2.1
- 2303 - Unreal 3.2beta* through 3.2 Release
- 2302 - Unreal 3.1.1 through 3.1.4
- 2301 - Unreal 3.1 Release
- 2300 - Unreal 3.0 Release

The compile flags as specified in protocol flags are:

- c : Server is chrooted (#define CHROOTDIR).
- C : Server has command line config (-f option) enabled (#define CMDLINE_CONFIG).
- D : Server is in debugmode (#define DEBUGMODE).
- F : Using filedescriptor lists.
- h : Server is compiled with hub support (#define HUB or answer "Hub" to relevant ./Config prompt).
- i : Server shows invisible users in /TRACE.
- n : NOSPOOF (pingcookies) is enabled (#define NOSPOOF or answer "Yes" to relevant ./Config prompt).
- V : Server is using valloc().
- W : Windows IRCd.
- Y : Syslog logging enabled.
- 6 : Server has IPv6 support (#define INET6 or answer "yes" to relevant ./Config prompt).
- P : Server is using poll().
- e : Server has SSL Support (#define USE_SSL or answer "yes" (and have ssl libraries installed) to relevant ./Config prompt).
- O : Server has OperOverride enabled (#undef NO_OPEROVERRIDE or answer "no" to relevant ./Config prompt).
- o : Server has disabled Oper verify (#undef OPEROVERRIDE_VERIFY or answer "no" to relevant ./Config prompt).
- E : Server has extended channel mode support.
- 3 : 3rd party modules are loaded or some system libraries are wonky.
- m : Private message handling is 'tainted' (one or modules registered a USERMSG hook).
- M : Channel message handling is 'tainted' (one or modules registered a CHANMSG hook).
- Additional Version flags can be added by 3rd-party modules.

## 2.4 EOS - End Of Synch (TOKEN: ES)

Syntax: ES

Marks the end of the synching process. This is really optional, but it might be a good idea to send it anyway when you really are done synching. Once you send this, unreal will announce "Client connecting" or "Client exiting" notices (to those with snomask +F) for users (unless your server is U:Lined), and joins will be counted toward channel flood controls (chanmode +f).

Sending EOS only marks your server as synched, but does not do so for servers behind you. EOS would need to be sent on those servers' behalf as well.

## 2.5 NETINFO - Network Information (TOKEN: AO)

Syntax: AO maxglobal currenttime protocolversion cloakhash 0 0 0 :networkname

This tells the other server your current network configuration. The max global is the highest number of concurrent users network-wide that this server has seen. The current time is a timestamp value. Protocolversion is the same as that in the SERVER command. Cloakhash is a hash representing the configured cloak keys. It may be a * if you are implementing services. The network name is that specified in set::network-name. The cloak-prefix is currently not sent here (and thus unreal won't generate warning for mismatching cloak prefixes, but they should be the same anyway).

It is NETINFO, not EOS, that triggers the "Link bla bla bla is now synched" notices, but NETINFO does not imply synching is actually complete (see EOS).

# 3 User Operations

One important function of servers is it must notify all other servers about all of the users behind it. These commands represent the operations that can result in the change of a user's global state.

## 3.1 NICK - User Introduction and Nick Change (TOKEN: &)

Syntax (nick change): `:oldnick & newnick :timestamp`

This format of the NICK message indicates an existing user is changing his or her nickname. If a collision occurs, see the section on Nick Collisions below. The timestamp is the new nickname's timestamp.

Syntax (normal): `& nick hopcount timestamp username hostname server service-identifier-token :realname`

Syntax (NICKv2): `& nick hopcount timestamp username hostname server service-identifier-token +usermodes virtualhost :realname`

Syntax (NICKv2+CLK): `& nick hopcount timestamp username hostname server service-identifier-token +usermodes virtualhost cloakhost :realname`

Syntax (NICKv2+NICKIP): `& nick hopcount timestamp username hostname server service-identifier-token +usermodes virtualhost nickipaddr :realname`

Syntax (NICKv2+NICKIP+CLK): `& nick hopcount timestamp username hostname server service-identifier-token +usermodes virtualhost cloakhost nickipaddr :realname`

Note: Because each server normally does its own cloak generation, Unreal does not expect to receive NICK messages with the CLK info, so do not send it. It will send this info to a server it has received a PROTOCTL CLK from however.

This format of the NICK message introduces a new user to the network. If PROTOCTL VHP is enabled, the user's cloaked host is put in the virtualhost field, otherwise it'll be * unless the user is +t. With the addition of CLK, VHP is no longer necessary for determining the cloak host.

### 3.1.1 Nick Collisions

A nick collision occurs when a server receives a NICK message (or & token) introducing a user that the server already sees on the network. When a collision occurs, one or both of the colliding clients must be disconnected. The timestamp is examined to determine which client loses. The client with the earlier timestamp remains. If both clients have equal timestamps, both are removed. Currently, Unreal handles NICK collisions both passively and agressively:

- Aggressive Handling: The server actively sends a KILL message back across the link to terminate that end's client.
- Passive Handling: Upon receipt of a NICK message that should "win", the server simply silently exits it's own client.

## 3.2 MODE, UMODE2 - User Mode Change (TOKEN: G or |)

Syntax (MODE): `:user G user modechange`

Syntax (UMODE2): `:user | modechange`

This indicates a usermode change. The modechange can consist of zero or more strings of characters, each prefixed with either a + or -; the only delimiter between them being said + or -. If no + or - is at the beginning of the mode string, a + should be implied.

Some user modes are never sent between servers. Specifically, usermode +s and +O are not sent between servers. Modules can define additional usermodes that also might not be sent between servers. The UMODE2 saves bandwidth by not including the redundant target field for usermode changes, so use it when possible.

## 3.3 QUIT - User Disconnect (TOKEN: ,)

Syntax: `:user , :reason`

This command indicates that a user has disconnected. The reason field is filled in with the reason the user disconnected, which will be any of: quit message provided by the user in a /quit command, kill message for local operator kills, "Client exited" if the user does a brutal quit (clean (by TCP's definition) disconnect without sending a QUIT message), or a socket error message if present.

The QUIT message must NOT be prefixed when passing on to other servers. Only local user quit messages are affected by set::prefix-quit.

## 3.4 KILL - Force Disconnect (TOKEN: .)

Syntax: `:source . target :killpath!source (reason)`

Used to indicate that an operator has used KILL on a user not on the same server. Anything beyond the last ! in the kill path is used as the reason. The source (reason) part is simply a standard used by Unreal. As each server passes on a KILL message, it usually prepends the bottommost part (up to the first .) of it's name followed by a ! character. When unreal receives a KILL from a directly connected irc operator, it will usually add that oper's vhost (or realhost if -x) as the first hop in the kill path, then follow with it's own name as mentioned before if it is passing to another server.

A server can also send KILLs on it's own. This is done in cases involving nickname collisions, fake senders, bad direction, and other cases of protocol errors. Usually, in these cases, the server puts it's own name as the source, and also prefixes with bottompart! like for any other ircop on that server. For example: @3 . someone :irc!irc.example.com (Nick collision)

## 3.5 SETHOST/CHGHOST - Change virtual host (TOKEN: AA or AL)

Syntax (SETHOST): `:source AA newvhost`

Syntax (CHGHOST): `:source AL target newvhost`

Indicates the change of a user's virtual host. Currently, servers are expected to assume UMODE2 +xt on the target user in both commands. (In the case of SETHOST, the target is the sender.) Servers using PROTOCTL VHP will receive the cloaked host in a SETHOST message when a user activates his cloaked host. A server can also send CHGHOST (from one of it's opered clients) to change a user's hostname. This is generally used by HostServ implementations. To disable a cloaked host, use CHGHOST to set the user's virtual host equal to his real host, or use SVSMODE -xt, but the latter requires services.

## 3.6 SETIDENT/CHGIDENT - Change a user's username (TOKEN: AD or AZ)

Syntax (SETIDENT): `:source AD newusername`

Syntax (CHGIDENT): `:source AZ target newusername`

Indicates the change of a user's username. No usermode change is associated with this. Unreal does not use a distinguished virtual username, so servers should only keep the original username (from the NICK message) if they intend to allow the user to reset the original username. Servers can use CHGIDENT to change a user's username.

## 3.7 SETNAME/CHGNAME - Change a user's realname (TOKEN: AE or BK)

Syntax (SETNAME): `:source AE :newrealname`

Syntax (CHGNAME): `:source BK target :newrealname`

Indicates the change of a user's realname. No usermode change is associated with this. Unreal does not use a distinguished virtual realname, so servers should only keep the original realname (from the NICK message) if they intend to allow the user to reset the original realname. Servers can use CHGNAME to change a user's username. Note that servers must NOT check that the sender be an IRCop in SETNAME - normal users are permitted to use SETNAME.

## 3.8 WHOIS - User Information (TOKEN: #)

Syntax: `:source # [from-server ]nick`

Requests the information on a user. This works exactly like the user /whois command - in fact, the source parameter must be a user, or the command will do nothing. from-server is the server to request the information from; if a server recives a WHOIS message without this parameter, it should return its own information on the user, otherwise it should pass the message to the given server. Note that from-server may name a user instead of a server (such as when a user uses /whois nick nick), in which case the the nick should be interpreted as naming the server that user is on. nick may be several users seperated by commas, but may not contain wildcards.

The reply to a WHOIS message uses the same numeric replies as the user command.

# 4 Server Operations

This is different from server negotiation. Negotiation is when you are first connecting. Server introduction is used for introducing additional servers behind an existing server (aka hubbing). Hubbing is limited as specified by the hub, leaf, and leafdepth parameters in the link block and attempted violation of a hub restriction results in termination of the link. If no hub or leaf directive is given your server is a leaf by default, so any introduction of any server behind you would be an automatic drop. U:Lines don't matter here; services must be configured as a hub in the link block. The reason is U:Line is a permission rule, but hub privilege is a network structure rule.

## 4.1 SERVER - Server Introduction (TOKEN: ')

Note: This command is also used for negotiation. Be warned that the token for this command is NOT VALID at that time! See section 2.3 for the syntax for negotiation.

Syntax (without PROTOCTL NS): `:source SERVER new.server hopcount :description`

Syntax (with PROTOCTL NS): `@sourcenumeric SERVER new.server hopcount numeric :description`

The command indicates that the server named new.server is being introduced by the source (the source is the server which new.server is directly linked to). The hopcount will be the number of links the receiving server would have to cross to reach new.server. In other words, new.server introduced itself with a hopcount of 1, and as the SERVER message is passed along, hopcount is incremented.

As an example, a services server faking a SERVER message for JUPE functionality would use a hopcount of 2.

## 4.2 SQUIT - Server Removal (TOKEN: -)

Syntax: `:source SQUIT server.name :reason`

From an IRCop or when server.name is not behind the source, this command requests the removal of the specified server.name. The command in this case is treated very much like KILL in the respect that the message is broadcasted to all servers, except server.name and any servers behind it. When the SQUIT reaches server.name's uplink, that server closes the link to server.name (which would then generate it's own SQUIT on behalf of it's uplink for the servers behind it).

A server can also use SQUIT in the same manner as QUIT to note the removal of a server behind it, or that it itself is quitting. In the former case, server.name is behind source, and the message is forward on to all other servers. In the latter case, source and server.name are equal, the receiving server closes the link and forwards the SQUIT message.

Unreal closes a direct link by simply sending an ERROR message and then closing the TCP connection. This typically causes the other end to generate an SQUIT bearing the message "Client exited" or similar, however, the ERROR will usually cause the server to send a message to all IRCops.

## 4.3 SDESC - Server Description (TOKEN: AG)

Syntax: `:source AG :newdesc`

The server to which source is connected to should have it's description updated to newdesc. This does NOT include the VL inforamtion.

## 4.4 PING - Live Connection Query (TOKEN: 8)

Syntax: `8 source[ :destination]`

Used to check if a connection is still live if it has been "quiet" for a certain amount of time. Typically, unreal will send PING requests at intervals determined by the class::pingfreq setting. PINGs originating from the direct uplink will use the token, but it seems PINGs originating from a distant server will not.

The response to a PING is sent with the PONG command.

When receiving a two-parameter PING, the second parameter is the target. If the target isn't you, you can either reply on behalf of that target (using its name instead of yours), or if there is a real connection representing the target, forward the PING to the target.

## 4.5 PONG - Live Connection Reply (TOKEN: 9)

Syntax: `9 source[ :destination]`

Used to respond to a PING query.

Responding to a ping: Once a PING is received, you usually have an amount of time to respond equal to your class::pingfreq. The correct response will always have two parameters. If you received one parameter, then the received parameter becomes the second parameter of your response, and the first parameter is your server name. If you received two parameters, the response returns both parameters in reverse order.

For example, the response to `8 uplink.server` is `9 my.name uplink.server`, while the response to `PING distant.server your.server` is `9 your.server distant.server`. Unreal typically includes a : prior to the last parameter. This isn't required if that parameter contains no spaces, but it is especially important to not include the colon when reversing the parameters, or else Unreal mistake it for a single-parameter PONG.

If a two-parameter PONG is received, the second parameter names the target. If the target is not you, and a real connection represents that target, you should forward the PONG message via that connection.

## 4.6 STATS - Server Stats (TOKEN: 2)

Syntax: `:source 2 [type [server] [extended-params]]`

Requests statistics or configuration information from a server. This command is used to transport cross-server STATS requests from users (eg: /stats o other.server), and should only be sent from a user (not a server). With no parameters, this will cause unreal to simply dump its help output. type is the type of stats to request, server names a server (or a user on that server) to request stats from, and extended-params is used to filter output from STATS G, etc. When received, it is up to the receiver to determine what stats to support and how to reply, but generally numeric replies are used. For the list of unreal's stats types, type /stats in a client for the helptext dump.

Note: Stats set as oper-only (see set::oper-only-stats) will be refused from a server. In this case, it will be necessary to send the stats request from a psuedo-oper (such as a services agent, etc) for services/stats/etc.

# 5 Channel Operations

These commands deal with the state of channels across the network. Unreal only supports Network Channels, where the first character is a # character.

## 5.1 SJOIN - Channel Burst (TOKEN: ~)

Syntax: `@servernumeric ~ timestamp channel +modes[ modeparams] :memberlist &ban "exempt 'invex`

Timestamp is the channel timestamp. Modes should only include those in the last three mode sets listed in CHANMODES. Modeparams is one parameter for each mode character that requires one. Memberlist is a series of users (all of which must at least be behind the server sending the SJOIN), each user is prefixed with one or more characters indicating their status. Owners (+q) are prefixed with *, admins (+a) ~, ops (+o) @, halfops (+h) %, voices (+v) +. Normal users are not prefixed with anything. Ban, ban exception, and invite exception masks are also included, with bans prefixed with &, ban exceptions prefixed with ", and invite exceptions with '. Note that when a &, " or ' is encountered as the first character, further processing of ~, *, @, %, or + characters must not continue because ban, exempt, and invite masks can contain any of those characters. (Plus it's just not right for a ban mask to be marked as a channel admin...)

If the channel didn't already exist it is created with the information given in the SJOIN. Otherwise the timestamp is used to determine how the SJOIN information is handled. As a given, all members are joined into the channel, regardless. The mode information (modes, modeparams, memberlist prefixes, bans, exempts, and invites) is subject to the timestamp rules:

- If the channel's current timestamp is equal to the timestamp in SJOIN, then the mode information is merged.
- If the channel's current timestamp is less than the SJOIN timestamp, then the mode information is ignored.
- If the channel's current timestamp is greater than the SJOIN timestamp, then the channel's existing mode information is cleared (for example, deop, etc all local clients), and the SJOIN mode information is added.

When merging modes, conflicting modes (including +p vs +s, differing +l limits or +k keys, etc) are handled as follows:

- Private (+p) vs. Secret (+s): Secret (+s) is preferred. Private (+p) is removed. (Note: there is a bug in Unreal versions prior to 3.2.3 in which a desynch will occur in which one side is +p and the other is +s. Update to Unreal 3.2.4 if you have problems with this.)
- Strip Color (+S) vs. Block Color (+c): Block (+c) is preferred. Strip (+S) is removed. (Note: Bug for +p vs. +s in prior unreal versions apply here as well.)
- Channel Limit: Numericly larger limit is preferred (for example, +l 30 versus +l 15 : +l 30 wins).
- Channel Key: "Larger" key (as defined by strcmp) is preferred (for example, +k moo versus +k meow : +k moo wins).
- Channel Link: "Larger" link name (as defined by stricmp - not case sensitive) is preferred (for example, +L #moo versus +L #meow : +L #moo wins, but +L #Meow versus +L #meow : values are equal).
- Flood String: Not really sure on this. I think larger value in each component wins.
- Join-Throttle: Highest of time period wins, if equal, highest of join amount wins (so +j 3:40 beats +j 5:20 but +j 5:20 beats +j 3:20).
- Parameterized modes in third party modules will define their own conflict resolution formula.

## 5.2 JOIN - Channel Join (TOKEN: C)

Syntax: `:source C #channel`

Indicates a user has joined a channel. Only one channel is sent this way, and the key is not sent even if the user gave one one joining. If the channel parameter is the special "0" case, the server must interpret the message as a PART for all channels the user is on.

## 5.3 PART - Channel Part (TOKEN: D)

Syntax: `:source D #channel[ :reason`]

Indicates a user has left a channel. Only one channel is sent this way. The reason parameter may be left out if no reason was given.

## 5.4 KICK - Channel Kick (TOKEN: H)

Syntax: `:source H #channel user :reason`

Orders the forced removal of user from #channel with the given reason. When updating state for this command, it should be the same as if :user PART #channel had been received - the user is removed from #channel's memberlist.

## 5.5 MODE - Channel Mode (TOKEN: G)

Note: This is the same command as that used for usermode changes.

Syntax: `:source G #channel modechange modeparams[ timestamp]`

Changes the specified modes on the given channel. If the source is a server and the last parameter is numeric, it is interpreted as timestamp (although it can also be consumed as a parameter for modes. For example: :server.name MODE #channel +l 4 <-- 4 will be a timestamp and the +l parameter). When a mode change is timestamped in this way, the mode is treated as it is with SJOIN: the MODE message is ignored if the timestamp is greater than the channel timestamp. (If the timestamp is equal, the mode is simply added replacing any conflicting modes already in place.)

A services implementation can easily clear all entries in a list mode such as bans with SVSMODE (see below).

## 5.6 INVITE - Invite a user to a channel (TOKEN: *)

Syntax: `:source * target #channel`

Sends to target an invitation to join #channel. If the source is a channel operator on #channel, or a U:Lined server, the invitation grants the user the temporary ability to join the channel regardless of any bans or some restricting channel modes (not +O or +A).

## 5.7 SAJOIN - Channel Force Join (TOKEN: AX)

Syntax: `:source AX targetuser #channel`

This requests the forced join of targetuser to #channel. This type of forced join overrides bans, and most modes. The server to which targetuser is connected to must actually acknowledge the join for it to occur. Service implementations may ignore this command, as they would only ever receive it if an SAJOIN was targeted at a service client, in which case it should be ignored...

## 5.8 SAPART - Channel Force Part (TOKEN: AY)

Syntax: `:source AY targetuser #channel[ :reason]`

This requests the forced part of targetuser from #channel. This is slightly different from a KICK in that the user's removal is announced with PART. The server to which targetuser is connected to must actually acknowledge the part for it to occur. Service implementations may ignore this command, as they would only ever receive it if an SAPART was targeted at a service client, in which case it should be ignored...

The reason field is optional. If provided the acknowledging PART message should prefix the message with "SAPart:".

## 5.9 SAMODE - Channel Force Mode (TOKEN: o)

Syntax: `:source o #channel modechange modeparams`

This has the same parameters as for MODE. The only difference is that servers probably will never receive this (but is best to document just in case), and that absolutely NO permission checking is done on anything.

## 5.10 TOPIC - Channel Topic (TOKEN: ) )

Syntax: `:source ) #channel nick timestamp :topic`

Changes the channel topic information. This format is used when synching, as well as when a topic is changed normally. Nick is the user who changed the topic (depending on compile options, it can be just nick or a full nick!user@host), timestamp is when the change occured, and topic is the new topic text. Normally, only a newer timestamp will actually change the topic, but a U:Lined server can use an older timestamp as well (such as for TOPICLOCK).

# 6 Services Commands

These are commands typically employed by a service implementation, in addition to some of the normal commands. All of the commands listed here require the sender to be correctly U:Lined. This means that the services server name must appear within a ulines {} block in the unrealircd.conf configuration for ALL servers in the network. All servers and clients behind a U:Lined server are themselves U:Lined.

## 6.1 SVSKILL - Force Disconnect by Service (TOKEN: h)

Syntax: `:source h target :reason`

This command is similar to KILL but differs in several ways. First of all: there is no mutilation of the reason value. The reason given is the exact reason used to generate QUIT messages sent to users. Second, it is silent; no server notice is generated in response to this command. Third, it can only be used by a U:Lined server or client (such as services).

Because this command can be dangerous in the hands of an abusive person, service implementations should avoid granting humans control over the reason parameter. In cases of commands where a person has control over such parameter, either use a regular KILL instead, or otherwise modify the reason so that operators can be held accountable if necessary.

## 6.2 SVSMODE, SVS2MODE - Force User Mode Change (TOKEN: n or v)

Syntax (SVSMODE): `:source n target +usermodes`

Syntax (SVS2MODE): `:source v target +usermodes`

Judging by these commands alone, you'd think they are identical. Both commands force a usermode change to occur. This is typically used by services to set +r on a user who has successfully identified. They differ in that SVS2MODE also sends the mode change to the user, while SVSMODE does not (hidden mode change).

SVSMODE and SVS2MODE also give special treatment to usermode +d. Rather than setting the deaf mode like you might expect, SVS(2)MODE +d allows services to change a user's services stamp (which is given in the NICK message). This could allow services to set the service stamp to an easily identifiable value that could then be used to say "hey, this person identified already". The syntax of this is: +d newservice-identifier-token and can be combined with setting other usermodes as well. The deaf mode can be set by using +d without the service stamp parameter; however, in this case you cannot set the service stamp in the same SVS(2)MODE message.

Note: Do NOT use SVSMODE to remove IRCop status from a user. Use the SVSO command for that instead.

Alternatively, target can name a channel. In this case, the mode change parameter can consist of a - character, followed by any or all of: b, e, I, q, a, o, h, or v. These characters cause the corresponding lists to be cleared of all entries. For example: SVSMODE #channel -b removes ALL bans from #channel, and SVSMODE #channel -qaohv turns ALL users on #channel into normal users (removes all owner, admin, op, halfop, and voice status). In this case, the uplink will acknowledge with a MODE listing the bans, etc that were removed.

To completely clear a channel of all modes: MODE #channel -cfijklmnprstzACGMKLNOQRSTVu (plus any added by third-party module) followed by SVSMODE #channel -beIqaohv.

## 6.3 SVSSNO, SVS2SNO - Forced SNomask Change (TOKEN: BV or BW)

Syntax (SVSSNO): `:source BV target +snomasks`

Syntax (SVS2SNO): `:source BW target +snomask`

Changes a user's snomasks. The difference between SVSSNO and SVS2SNO is the same as with SVSMODE versus SVS2MODE. If the user is not +s, you must add it via SVSMODE +s. For example:

    :OperServ v someuser +s
    :OperServ BW someuser +ks

## 6.4 SVSNICK - Forced Nick Change (TOKEN: e)

Syntax: `:source e target newnick :newtimestamp`

Forces the specified user to change his nick to newnick and also sets the nick timestamp to newtimestamp (so, for example, services could protect identified users from a nick collision by simply setting the nick timestamp to something way less than "now" - though currently this requires actually changing the nick too). SVSNICK requires the server to which the target is connected to acknowledge the nick change. If the user specified by newnick already exists, then target will be disconnected (even if it's something like a case-change).

## 6.5 SVSJOIN - Forced Join (TOKEN: BX)

Syntax: `:source BX target #channel`

This is identical to SAJOIN with a few exceptions: 1) It is U:Line-only. 2) No opernotice on use. 3) Bans and restricting modes are respected, a prior INVITE message must be sent to cause bans to be ignored.

## 6.6 SVSPART - Forced Part (TOKEN: BT)

Syntax: `:source BT target #channel :reason`

Also identical to SAPART with a few exceptions: no static prefix on the optional part reason, and no global notice, and requires a U:Line. Usage recommendation of SVSPART versus KICK is the same as for SVSKILL versus KILL.

## 6.7 SVSO - Oper Permissions (TOKEN: BB)

Syntax: `:source BB target flagchanges`

This allows a service to add or remove IRCop permission flags for a user. Flagchanges is formatted similar to that of MODE with the exception that operflags are used instead of usermodes. If the change string consists only of -, then all oper permissions, usermodes, and snomasks are removed (as if the user had himself typed MODE nick -Oo).

If you are granting IRCop permissions to a user who is not currently an IRCop, you should follow up with an SVSMODE +o or SVSMODE +O as appropriate. For example:

    :OperServ BB somenick +o
    :OperServ BW somenick +cefknoqsSv
    :OperServ AL somenick local.oper.somethinghere.net
    :OperServ v somenick +Ohs

## 6.8 SVSNOOP - Oper Lockdown (TOKEN: f)

Syntax: `:source f (op)server.name`

The (op) parameter is either a + or - indicating if NOOP mode should be activated (+) or deactivated (-). When NOOP mode is activated, all IRCops on the server are deopered (including local operators) and the /oper command is disabled. IRCop privileges can still be granted through use of SVSO. On UnrealIRCd, it is not necessary to masskill all IRCops on the nooped server, as they are deopered automatically.

## 6.9 SVSNLINE - RealName Ban (TOKEN: BR)

Syntax: `:source BR op reason :realname mask`

Op is either + (add) or - (remove). In the case of +, reason is a space-escaped string (all space chars are encoded as _). If -, reason is ignored.

## 6.10 SVSFLINE - File Ban (TOKEN: BC)

Syntax (add): `:source BC + filemask :reason`

Syntax (remove): `:source BC - filemask`

Syntax (clear): `:source BC *`

Adds or removes a DCCDENY item for the specified filemask on all servers. These DCCDENYs are hard dccdenies - the /dccallow command cannot override it. The last form removes all dccdenies added via SVSFLINE.

# 7 Messaging

What good is Internet Relay CHAT if users cannot CHAT? This section addresses the commands through which arbitrary user messages are sent.

## 7.1 PRIVMSG, NOTICE - Simple Message Transmission (Token: ! or B)

PRIVMSG Syntax: `:source ! target :message`

NOTICE Syntax: `:source B target :message`

Sends a messages to the given target. The target either names a single client, or identifies a list of clients in which the message is to be sent to. The available targets include:

- nickname: Names a single user to whom the message is delivered.
- nickname@servermask: Also names a single user, but the message will only be delivered if the user is connected to a server matching the specified servermask. This is typically used for sending messages to services. The target must not be changed at any point along the path it must travel for delivery, even up to the final receipt of the message by the target. This allows the target to know it has been sent a message in this way.
- #channelname: Sends a message to all users on the specified channel (except when channel is a moderated auditorium (+mu), in which case the wierd +mu sending behavior goes off).
- modeprefix#channelname: Sends a message to all users on the given channel having the given status or higher. For example: + means all voices, halfops, etc.
- $servermask: Sends a message to ALL users on all servers matching the specified servermask (known as a server broadcast message). The RFC requirements of having a TLD with no wildcards is not applied to U:Lined clients.

Unreal does not support the #hostmask format.

## 7.2 SENDUMODE, SMO - Usermode-based Delivery (TOKEN: AP or AU)

Syntax: `@servernumeric AU umode :message`

Sends the specified message to all users with the given mode. Only one usermode may be given. This is a server-only command if you can't tell from the sender prefix :) .

The message will be displayed as coming from the receiving client's own server. It may be appropriate to add a "*** Notice (or other leader here) -- from blah:" if you wish to clarify where the message is from.

## 7.3 SENDSNO - SNomask-based Delivery (TOKEN: Ss)

Syntax: `@servernumeric Ss snomask :message`

Sends the specified message to all users with the given snomask. Only one snomask may be given. This is a server-only command if you can't tell from the sender prefix :) .

The message will be displayed as coming from the receiving client's own server. It may be appropriate to add a "*** Notice (or other leader here) -- from blah:" if you wish to clarify where the message is from.

## 7.4 CHATOPS - IRCop Chat (TOKEN: p)

Syntax: `:source p :message`

Sends the message to all IRCops on all servers.

## 7.5 WALLOPS - Wallop Chat (TOKEN: =)

Syntax: `:source = :message`

Sends the message to all users with usermode +w, whether they are ircops or not.

## 7.6 GLOBOPS - FailOp Chat (TOKEN: ])

Syntax: `:source ] :message`

Send the message to all IRCops with usermode +g.

## 7.7 ADCHAT - Admin Chat (TOKEN: x)

Syntax: `:source x :message`

Send the message to all Server and Network Admins (usermode +A).

## 7.8 NACHAT - NetAdmin Chat (TOKEN: AC)

Syntax: `:source AC :message`

Send the message to all Network Admins (usermode +N).

# 8 Ban Control

Sometimes, you have the misfortune of encountering a user who has no purpose but to serve as an annoyance to your server or network. These commands transmit network-wide ban information amongst each other.

## 8.1 TKL - Master Ban Control (TOKEN: BD)

The TKL command seems to have one oddity about it: the real ban source is included in the TKL command rather than in the sender prefix. Most likely this is done for synching reasons (so that the *line ban can be credited to the proper person even if he/she is offline). For this reason, the command syntax is given without any sender prefix at all. It is still permissible to use one, however.

### 8.1.1 GLINE - Network-wide user@host ban

Add Syntax (TKL): `BD + G userpart hostpart source expiretimestamp settimestamp :reason`

Remove Syntax (TKL): `BD - G userpart hostpart source`

Adds and Removes Network-wide user@host bans, known as G:Lines. The GLINE command itself must not be used. The userpart and hostpart are the user portion and hostname portion of the ban mask. The expiretimestamp is 0 if the G:Line should not expire, otherwise it will expire at the given time. It is an absolute time, not relative, thus it's imperitive to have reasonably synchrnoized clocks or bans may be removed too early or even immediately!

### 8.1.2 GZLINE - Network-wide IP ban

Add Syntax (TKL): `BD + Z * ipmask source expiretimestamp settimestamp :reason`

Remove Syntax (TKL): `BD - Z * ipmask source`

Adds and Removes Network-wide IP bans, known as Global Z:Lines. The GZLINE command itself must not be used. Ipmask permits CIDR notation as well as wildcard masks.

### 8.1.3 SQLINE, UNSQLINE - Network-wide Nickname ban (TOKEN: c or d)

Add Syntax (TKL): `BD + Q hold nickmask source expiretimestamp settimestamp :reason`

Add Syntax (SQLINE): `:source c nickmask :reason`

Remove Syntax (TKL): `BD - Q hold nickmask source`

Remove Syntax (UNSQLINE): `:source d nickmask`

In the TKL syntax, the hold parameter is either a * to mark the qline as a nick ban, or an H to mark it as a services hold. A services hold does not trigger qline rejection notice, and is typically used by NickServ to reserve registered nicks until they are released by the owner. The (UN)SQLINE syntax can only be used by a server, but any user can be used as the source for the TKL syntax. Unlike G and GZ lines, Q:Lines do not cause existing matching users to be disconnected or otherwise affected.

The TKL syntax is preferred, since it is more flexible, but (UN)SQLINE is permitted for compatibility.

### 8.1.4 SPAMFILTER - Message Spam Filtration System

Proper use of spamfilter in TKL commands requires use of PROTOCTL TKLEXT, which increases the number of parameters allowed in TKL.

Add Syntax (TKL): `BD + F target(s) action source 0 settimestamp tklduration tklreason :regex`

Remove Syntax (TKL): `BD - F target(s) action source 0 settimestap :regex`

Adds and Removes network-wide spamfilters. The SPAMFILTER command itself must not be used. See http://vulnscan.org/UnrealIrcd/unreal32docs.html#feature_spamfilter for a list of valid targets. For actions, a single character is used to identify the action to be taken:

- K (kill) - The user is simply disconnected, with the reason given.
- S (tempshun) - A temporary shun is placed on the user. This shun is applied only to that user, and disappears if the user reconnects.
- s (shun) - A regular shun on the user's IP address is added. This causes all users with the same hostname to be shunned, but they will also stay shunned if they reconnect.
- k (kline) - A K:Line is added on the user's IP address.
- z (zline) - A Z:Line is added on the user's IP address.
- g (gline) - A G:Line is added on the user's IP address.
- Z (gzline) - A Global Z:Line is added on the user's IP address.
- b (block) - Messages (or users!) matching the filter are simply blocked.
- d (dccblock) - The user is prevented from sending files using DCC for the remainder of his session (in other words, until he quits).
- v (viruschan) - User is removed from all channels, joined to the viruschan as defined in conf, and cannot message anything but that channel.
- w (warn) - No action on the user is taken. Only the Spamfilter notice is sent to opers with snomask +S.

# 9 Base64 Tables

Historically, unreal used different base64 tables for sending NICK and SJOIN timestamps and sending NICKIP data. Currently, base64 is used only to encode NICKIP.

## 9.1 Table for NICKIP.

In this table, the IP is encoded in network byte order. In terms of IPs, this means the first byte of the address really is first. Each "digit" in the base64 encoded IP corresponds to 6 bits of the IP address.

An IPv4 address is 32 bits, so 6 base64 "digits" are needed. Since base64 requires values to come in multiples of 4 "digits", padding characters (=) need to be added if a value comes up short. In the case of IPv4 addresses, two are needed.

IPv6 addresses are 128-bit. They therefore need 22 base64 "digits" plus 2 pad characters.

     0 A            17 R            34 i            51 z
     1 B            18 S            35 j            52 0
     2 C            19 T            36 k            53 1
     3 D            20 U            37 l            54 2
     4 E            21 V            38 m            55 3
     5 F            22 W            39 n            56 4
     6 G            23 X            40 o            57 5
     7 H            24 Y            41 p            58 6
     8 I            25 Z            42 q            59 7
     9 J            26 a            43 r            60 8
    10 K            27 b            44 s            61 9
    11 L            28 c            45 t            62 +
    12 M            29 d            46 u            63 /
    13 N            30 e            47 v
    14 O            31 f            48 w         (pad) =
    15 P            32 g            49 x
    16 Q            33 h            50 y