DCC negotiation and connection
Overview of the DCC internals
What is DCC?
'DCC' stands for Direct Client Connection, it is used to exchange data directly between two IRC clients (with no IRC server in the middle).
DCC itself is not a well-defined protocol, but rather a set of sub-protocols with (more or less) standardized rules.
Sub-protocols are also (historically) called DCC types; this term often leads to confusion and it will become clear later.
Each sub-protocol has two main parts: The DCC negotiation and the DCC transfer.
The DCC negotiation part is used to request the DCC transfer and define its necessary parameters,
while the DCC transfer part is the real data transfer between clients.
The DCC negotiation requires a third entity that routes the negotiation data between clients, this is usually an IRC server.
This part of the protocol is the most tricky and difficult one, and is different for almost every DCC sub-protocol.
The constant scenario of the negotiation is more or less the following:
There are two IRC clients connected to the same IRC network and they want to exchange some data in a direct client connection.
Each client knows the other by nickname only (and eventually by the host displayed by the IRC server, but this cannot be trusted for several reasons), and can send text messages to each other by using the IRC network as data channel.
To initiate a direct client connection, one of the clients must start listening on some port (this is called passive client) and the other must connect to that port on the first client's machine (this is the active client).
Both clients must agree on who is the passive and who is the active client. The active client must also know the passive client's IP address and port (in order to be able to contact it).
Finally, both clients must agree on the transfer type that has to be initiated.
The negotiation exchanges these information between clients by using IRC as channel and CTCP messages as encoding method.
An example will make things clearer:
DCC chat is the simplest (and most widely implemented) DCC sub-protocol: it is used to exchange <cr><lf> separated text data between clients.
Assume that you want to establish a DCC chat connection to 'Sarah' that is currently connected to your IRC network (so she/he is an IRC user just like you). All you have to do is type sth as /dcc chat Sarah in your IRC client. The client will setup a listening socket on a random port chosen usually by the kernel of your OS. In this case YOU are the passive client, and Sarah is the active one.
Once the socket is ready to accept connections, your client will send a ctcp message to Sarah using the IRC connection (and protocol) as channel:
PRIVMSG Sarah :<0x01>DCC CHAT chat <ip_address> <port><0x01>
where <ip_address> is the address of the listening socket and <port> is the port that it has been bound to (these information are obtained after the socket has been setup). Once Sarah has received the CTCP message, and agreed to connect, her (active) client will attempt to connect to the specified <ip_address> and <port> (e.g. to your listening socket).
Once the connection has been established, it continues using the specific CHAT transfer protocol.
Some IRC clients allow modifications of this procedure:
First of all, the port to listen on can be specified by the user and not by the kernel; this is useful when the passive client is behind a firewall that shades some sets of ports. The IP address for the listening socket can be specified by the user as well (especially when the machine has more than one network interface).
A more challenging trick is to listen on a specified IP address and port and notify different ones to the remote user (e.g. <ip_address> and <port> parameters of the CTCP message are not the ones that the client is listening on). This is especially useful with transparent proxy firewalls that often are not transparent enough to allow the DCC connections. (If you have one of these firewalls you know what I'm talking about, otherwise just read on). KVIrc allows to avoid the usage of a third entity for the protocol negotiation too. You can setup a listening socket on a specified port and IP address without notifying anyone of this. You can also manually connect to a specified port and IP address without having been notified of a DCC request.
Is everything clear?...I don't think so... my English is really bad...
The DCC transfer part is different for every DCC sub-protocol, but it always happens over a direct client to client TCP connection.
There are two main standardized DCC sub-protocols that are widely implemented in IRC clients: DCC chat and DCC SEND.
DCC chat is quite simple and the protocol is more or less completely defined.
DCC SEND is a *real mess*, the original definition was not very flexible so many IRC clients tried to enhance both the negotiation and the transfer, leading often to incompatible implementations. (I can remember the Turbo File Transfer implemented by VIrc, the Send-Ahead enhancement implemented in many clients, the RESUME facility...)
Many clients introduced new DCC sub-protocols with non-standard implementations, leading again to client incompatibility.
Some of the notable sub-protocols are DCC Voice, DCC Draw, DCC Whiteboard...
This is the simplest and most standardized DCC sub-protocol. Almost every IRC client implements it.
It is used to exchange lines of text between the two clients.
The negotiation is quite simple, we assume that client A wants to establish a DCC chat connection to client B. client A sets up a listening socket and retrieves its address (IP address and port).
Once the socket is ready client A sends a CTCP request to B, in the following form:
DCC CHAT chat <ipaddress> <port>
Where <ipaddress> is a string representing an positive integer that is the A socket's IP address in network byte order, and where <port> is a string representing an positive integer that is the A socket's port.
The original purpose of the second chat string in the CTCP request is quite obscure, it was probably introduced to have the <ipaddress> as second parameter, as in the DCC SEND sub-protocol.
client B receives the CTCP, parses it, eventually asks the user for permission and connects to the specified IP address and port. The transfer protocol is quite simple, both clients can send text lines separated by <cr><lf> pairs.
Some clients use only <lf> as line terminator so the general idea is that one of <cr> <cr><lf> or <lf> can be used as line terminator.
As extension to the protocol, KVIrc allows <ipaddress> to be an IPv6 address in the standard hexadecimal notation, the connection will be made over the IPv6 protocol in this case (obviously if both clients support this feature).
(It is not clear why the original DCC specification used the unsigned int format instead of a standard string representation of the IP address... missing inet_aton() function on the target system?).
KVIrc adds the Secure Sockets Layer to the DCC chat protocol. In this case the negotiation string becomes:
DCC SCHAT chat <ipaddress> <port>
where SCHAT stands for Secure CHAT.
The external protocol is exactly the same but is built on top of a Secure Sockets Layer implementation (specifically OpenSSL). The connection will be encrypted with a private key algorithm after a public key handshake.
DCC SEND is another standard sub-protocol. Most clients implement this as well, many have tried to enhance it.
The basic DCC SEND protocol allows transferring a file from the requesting client to the receiving client.
The requesting client (the one that sends the file) is always passive and the receiving client is always active.
This is a huge protocol limitation since firewalled clients are often unable to accept incoming connections.
The negotiation protocol is more complex than DCC chat; we assume that client A wants to send the file F to client B.
client A sets up a listening socket and retrieves its IP address and port.
client A sends a CTCP request to client B in the following form:
DCC SEND <filename> <ipaddress> <port> <filesize>
<ipaddress> and <port> have the same semantics as in the DCC chat sub-protocol.
<filename> is the name (without path!) of the file to be sent, and <filesize> is (yeah), the file size.
client B receives the CTCP, parses it, eventually asks the user for confirmation and connects to the specified IP address and port; the transfer then begins.
client A sends blocks of data (usually 1-2 KB) and at every block awaits confirmation from the client B, that when receiving a block should reply 4 bytes containing an positive number specifying the total size of the file received up to that moment.
The transmission closes when the last acknowledge is received by client A.
The acknowledges were meant to include some sort of coherency check in the transmission, but in fact no client can recover from an acknowledge error/desync, all of them just close the connection declaring the transfer as failed (the situation is even worse in fact, often acknowledge errors aren't even detected!).
Since the packet-acknowledge round trip eats a lot of time, many clients included the send-ahead feature; the client A does not wait for the acknowledge of the first packet before sending the second one.
The acknowledges are still sent, but just a reverse independent stream.
This makes the DCC SEND considerably faster.
Since the acknowledge stream has non-zero bandwidth usage, no client can recover from an acknowledge error and having them as an independent stream is more or less like having no acknowledges, the Turbo ( :) ) extension has been added: client B will send no acknowledges and will just close the connection when he has received all the expected data.
This makes the DCC SEND as fast as FTP transfers.
The Turbo extension is specified during the negotiation phase, bu using TSEND as DCC message type (instead of SEND).
The Turbo extension is not widely implemented.
Later implementations have added the support for resuming interrupted DCC SEND transfers:
client A sets up the socket and sends the CTCP request as before.
If client B discovers that the file has been partially received in a previous DCC SEND session it sends a resume request in the following form:
DCC RESUME <filename> <port> <resume position>
Where <port> is the <port> sent in the DCC SEND request and <resume position> is the position in the file from where the transfer should start.
client A receives the request, parses it and eventually replies with:
DCC ACCEPT <filename> <port> <resume position>
client B receives the ACCEPT message, connects to client A and the transfer initiates as before.
The Send-ahead and Turbo extensions can obviously be used also in this case (But T is not prepended to the RESUME and ACCEPT messages).
The IPv6 extension can be used also in this sub-protocol, so <ipaddress> can be also an IPv6 address in hexadecimal notation.
KVIrc introduces the SSL extension also to DCC SEND. The protocol remains the same again but it is built on top of a Secure Sockets Layer implementation just like DCC chat.
With SSL the negotiation string becomes:
DCC SSEND <filename> <ipaddress> <port> <filesize>
where SSEND stands for Secure SEND.
The Turbo extension can be combined with the SSL extension too. In this case the second parameter of the negotiation string must be TSSEND or STSEND.
DCC RECV is the counterpart of DCC SEND. This is a KVIrc extension and is not standard yet.
The purpose of this sub-protocol will not be immediately clear, but read on for an explanation.
It is used to request a file from another client; we assume that client A knows that client B has a specific file and is able/wants to send it.
client A sets up a listening socket, retrieves its address and port and then sends a CTCP request to client B in the following form:
DCC RECV <filename> <ipaddress> <port> <resume position>
where <filename> is the name of the requested file without path, <ipaddress> and <port> have the usual meaning and <resume position> is the position from that the transfer should start from.
<ipaddress> can be an IPv6 address as well.
client B receives the CTCP message, parses it, looks for the file to send (in some unspecified way) and connects to the specified IP address and port. The transfer then begins just as in the DCC SEND, but in the inverse way: client B sends blocks of data to client A and client B sends back acknowledges.
This sub-protocol is useful in transferring data from clients that are behind a firewall and are not able to accept incoming connections (this is not possible with a normal DCC SEND). In this case the client that receives the file is passive and the client that sends it is active (as opposite to DCC SEND).
The Send ahead extension can be used also in this case and the Turbo extension is activated by prepending a T to the DCC message, TRECV instead of RECV. The SSL extension is activated by prepending an S to the DCC message, SRECV", STRECV or TSRECV.
This sub-protocol has an implicit resume capability and thus has no need for RESUME and ACCEPT messages.
DCC RECV requires the initiating (passive) client to know that the file to be transferred is available on the B's side and probably also know the file size. This sub-protocol does not specify how this information is obtained, but it will become clear soon that it can be obtained either manually (User B can simply tell the info to User A), or automatically (as in the DCC RSEND sub-protocol (keep reading)).
DCC RSend stands for Reverse Send. This is a KVIrc extension to the SEND protocol to allow firewalled clients to send files.
In fact, this is a half sub-protocol, since it defines only a part of the DCC negotiation; the transfer is defined by another sub-protocol (and specifically bu DCC RECV).
The requesting client (the one that sends the file) is active and the receiving client is passive.
Assume that client A wants to send a file to client B and that client A cannot accept incoming connections.
client A sends a CTCP request to client B in the following form:
DCC RSEND <filename> <filesize>
client B receives the request, parses it, eventually asks the user for confirmation, sets up a listening socket, retrieves its IP address and port and switches to the DCC RECV sub-protocol by effectively sending the following CTCP message:
DCC RECV <filename> <ipaddress> <port> <resume position>
The rest of the transfer is defined by the DCC RECV sub-protocol.
The Turbo extension is again activated by prepending a T to the RSEND string, so the initial CTCP will become:
DCC TRSEND <filename> <filesize>
The SSL extension is also activated by prepending an S to the RSEND string. It can be again combined with the Turbo extension. The negotiation parameter becomes then SRSEND, TSRSEND or STRSEND.
Easy, no? :)
This is again a half sub-protocol in fact since it defines only a part of the negotiation for file transfers.
It is also NON standard, since actually no client except KVIrc implements it (AFAIK).
DCC Get is used to request a file from a remote client. Assume that client A wants to request a file from client B (and assume that client A knows that B has that file and wants to send it).
client A sends a CTCP message to client B in the following form:
DCC GET <filename>
Where <filename> is a name of a file without path.
client B receives the message, parses it, looks for an association of the <filename> to a real filesystem file and starts one of the two DCC file transfer sub-protocols, DCC SEND or DCC RSEND.
client B should prefer the DCC SEND method and choose DCC RSEND only if it is not able to accept incoming connections.
This sub-protocol can be used by firewalled clients that can't accept connections but still want to request a file from another client, this one can fail only if both clients are firewalled (in this case no DCC transfer is possible at all).
This sub-protocol also does not need to magically know the file size, the size definition is found in the sub-protocol that the remote client will choose.
The association of <filename> with a real file on the B's machine is not explicitly defined by the sub-protocol; KVIrc uses an internal file-offer table with a list of files that are available for download.
The Turbo and SSL extensions are activated as usual, TGET, SGET, TSGET and STGET are supported.
DCC File Transfer
DCC SEND: Send a file, sender is passive, receiver is active (not good for firewalled senders)
DCC RECV: Receive a file, sender is active, receiver is passive (not good for firewalled receivers)
DCC RSEND: Send a file, sender is active, receiver is passive (not good for firewalled receivers)
DCC GGET: Receive a file, sender is passive if not firewalled, receiver active if sender not firewalled (will fail only if both are firewalled)
The Turbo extension disables the stream of acknowledges and is activated by prepending the 'T' character to the DCC sub-protocol name
The SSL extension causes a Secure Socket Layer to be used and is activated by prepending the 'S' character to the DCC sub-protocol name
DCC Voice is a KVIrc extension (there is a Windows client called VIrc that implements such a protocol, but it is incompatible with KVIrc).
DCC Voice allows audio level communication between two clients, the audio stream is compressed with a specified codec.
KVIrc currently supports the ADPCM (core support) and the GSM codec (if the libgsm is available on the target system).
TODO: Finish the DCC Voice doc :)
KVIrc supports another hack to the DCC negotiation, it recognizes XDCC as a DCC negotiation CTCP parameter.
This can be used to circumvent limitations of some IRC clients (read mIRC) that will not allow you to send a /DCC GET since it is an unrecognized DCC type.
XDCC has exactly the same meaning as DCC (at least in KVIrc).