NAME

AnyEvent::MP::Transport - actual transport protocol handler

SYNOPSIS

use AnyEvent::MP::Transport;

DESCRIPTION

This implements the actual transport protocol for MP (it represents a single link), most of which is considered an implementation detail.

See the "PROTOCOL" section below if you want to write another client for this protocol.

FUNCTIONS/METHODS

$listener = mp_listener $host, $port, <constructor-args>, $cb->($transport)

Creates a listener on the given host/port using AnyEvent::Socket::tcp_server.

See new, below, for constructor arguments.

Defaults for peerhost, peerport and fh are provided.

$guard = mp_connect $host, $port, <constructor-args>, $cb->($transport)
new AnyEvent::MP::Transport
# immediately starts negotiation
my $transport = new AnyEvent::MP::Transport
   # mandatory
   fh       => $filehandle,
   local_id => $identifier,
   on_recv  => sub { receive-callback },
   on_error => sub { error-callback },

   # optional
   on_eof   => sub { clean-close-callback },
   on_connect => sub { successful-connect-callback },
   greeting => { key => value },

   # tls support
   tls_ctx  => AnyEvent::TLS,
   peername => $peername, # for verification
;

PROTOCOL

The protocol is relatively simple, and consists of three phases which are symmetrical for both sides: greeting (followed by optionally switching to TLS mode), authentication and packet exchange.

the protocol is designed to allow both full-text and binary streams.

The greeting consists of two text lines that are ended by either an ASCII CR LF pair, or a single ASCII LF (recommended).

GREETING

All the lines until after authentication must not exceed 4kb in length, including delimiter. Afterwards there is no limit on the packet size that can be received.

First Greeting Line

Example:

aemp;0;fec.4a7720fc;127.0.0.1:1235,[::1]:1235;hmac_md6_64_256;json,storable;provider=AE-0.0

The first line contains strings separated (not ended) by ; characters. The first even ixtrings are fixed by the protocol, the remaining strings are KEY=VALUE pairs. None of them may contain ; characters themselves.

The fixed strings are:

protocol identification

The constant aemp to identify the protocol.

protocol version

The protocol version supported by this end, currently 0. If the versions don't match then no communication is possible. Minor extensions are supposed to be handled through additional key-value pairs.

the node endpoint descriptors

for public nodes, this is a comma-separated list of protocol endpoints, i.e., the noderef. For slave nodes, this is a unique identifier of the form slave/nonce.

the acceptable authentication methods

A comma-separated list of authentication methods supported by the node. Note that AnyEvent::MP supports a hex_secret authentication method that accepts a cleartext password (hex-encoded), but will not use this auth method itself.

The receiving side should choose the first auth method it supports.

the acceptable framing formats

A comma-separated list of packet encoding/framign formats understood. The receiving side should choose the first framing format it supports for sending packets (which might be different from the format it has to accept).

The remaining arguments are KEY=VALUE pairs. The following key-value pairs are known at this time:

provider=<module-version>

The software provider for this implementation. For AnyEvent::MP, this is AE-0.0 or whatever version it currently is at.

peeraddr=<host>:<port>

The peer address (socket address of the other side) as seen locally, in the same format as noderef endpoints.

tls=<major>.<minor>

Indicates that the other side supports TLS (version should be 1.0) and wishes to do a TLS handshake.

timeout=<seconds>

The amount of time after which this node should be detected as dead unless some data has been received. The node is responsible to send traffic reasonably more often than this interval (such as every timeout minus five seconds).

Second Greeting Line

After this greeting line there will be a second line containing a cryptographic nonce, i.e. random data of high quality. To keep the protocol text-only, these are usually 32 base64-encoded octets, but it could be anything that doesn't contain any ASCII CR or ASCII LF characters.

The two nonces must be different, and an aemp implementation must check and fail when they are identical.

Example of a nonce line:

p/I122ql7kJR8lumW3lXlXCeBnyDAvz8NQo3x5IFowE4

TLS handshake

If, after the handshake, both sides indicate interest in TLS, then the connection must use TLS, or fail.

Both sides compare their nonces, and the side who sent the lower nonce value ("string" comparison on the raw octet values) becomes the client, and the one with the higher nonce the server.

AUTHENTICATION PHASE

After the greeting is received (and the optional TLS handshake), the authentication phase begins, which consists of sending a single ;-separated line with three fixed strings and any number of KEY=VALUE pairs.

The three fixed strings are:

the authentication method chosen

This must be one of the methods offered by the other side in the greeting.

The currently supported authentication methods are:

cleartext

This is simply the shared secret, lowercase-hex-encoded. This method is of course very insecure, unless TLS is used, which is why this module will accept, but not generate, cleartext auth replies.

hmac_md6_64_256

This method uses an MD6 HMAC with 64 bit blocksize and 256 bit hash. First, the shared secret is hashed with MD6:

key = MD6 (secret)

This secret is then used to generate the "local auth reply", by taking the two local greeting lines and the two remote greeting lines (without line endings), appending \012 to all of them, concatenating them and calculating the MD6 HMAC with the key.

lauth = HMAC_MD6 key, "lgreeting1\012lgreeting2\012rgreeting1\012rgreeting2\012"

This authentication token is then lowercase-hex-encoded and sent to the other side.

Then the remote auth reply is generated using the same method, but local and remote greeting lines swapped:

rauth = HMAC_MD6 key, "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012"

This is the token that is expected from the other side.

tls

This type is only valid iff TLS was enabled and the TLS handshake was successful. It has no authentication data, as the server/client certificate was successfully verified.

Implementations supporting TLS must accept this authentication type.

the authentication data

The authentication data itself, usually base64 or hex-encoded data, see above.

the framing protocol chosen

This must be one of the framing protocols offered by the other side in the greeting. Each side must accept the choice of the other side.

Example of an authentication reply:

hmac_md6_64_256;363d5175df38bd9eaddd3f6ca18aa1c0c4aa22f0da245ac638d048398c26b8d3;json

DATA PHASE

After this, packets get exchanged using the chosen framing protocol. It is quite possible that both sides use a different framing protocol.

FULL EXAMPLE

This is an actual protocol dump of a handshake, followed by a single data packet. The greater than/less than lines indicate the direction of the transfer only.

> aemp;0;nndKd+gn;10.0.0.1:4040;hmac_md6_64_256,cleartext;json,storable;provider=AE-0.0;peeraddr=127.0.0.1:1235
> sRG8bbc4TDbkpvH8FTP4HBs87OhepH6VuApoZqXXskuG
< aemp;0;nmpKd+gh;127.0.0.1:1235,[::1]:1235;hmac_md6_64_256,cleartext;json,storable;provider=AE-0.0;peeraddr=127.0.0.1:58760
< dCEUcL/LJVSTJcx8byEsOzrwhzJYOq+L3YcopA5T6EAo
> hmac_md6_64_256;9513d4b258975accfcb2ab7532b83690e9c119a502c612203332a591c7237788;json
< hmac_md6_64_256;0298d6ba2240faabb2b2e881cf86b97d70a113ca74a87dc006f9f1e9d3010f90;json
> ["","lookup","pinger","10.0.0.1:4040#nndKd+gn.a","resolved"]

SEE ALSO

AnyEvent::MP.

AUTHOR

Marc Lehmann <schmorp@schmorp.de>
http://home.schmorp.de/