ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Transport.pm
(Generate patch)

Comparing AnyEvent-MP/MP/Transport.pm (file contents):
Revision 1.8 by root, Mon Aug 3 14:58:13 2009 UTC vs.
Revision 1.15 by root, Tue Aug 4 07:47:29 2009 UTC

1=head1 NAME 1=head1 NAME
2 2
3AnyEvent::MP::Transport - actual transport protocol 3AnyEvent::MP::Transport - actual transport protocol handler
4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 use AnyEvent::MP::Transport; 7 use AnyEvent::MP::Transport;
8 8
9=head1 DESCRIPTION 9=head1 DESCRIPTION
10 10
11This is the superclass for MP transports, most of which is considered an 11This implements the actual transport protocol for MP (it represents a
12implementation detail. 12single link), most of which is considered an implementation detail.
13 13
14See the "PROTOCOL" section below if you want to write another client for 14See the "PROTOCOL" section below if you want to write another client for
15this protocol. 15this protocol.
16 16
17=head1 FUNCTIONS/METHODS 17=head1 FUNCTIONS/METHODS
43Creates a listener on the given host/port using 43Creates a listener on the given host/port using
44C<AnyEvent::Socket::tcp_server>. 44C<AnyEvent::Socket::tcp_server>.
45 45
46See C<new>, below, for constructor arguments. 46See C<new>, below, for constructor arguments.
47 47
48Defaults for peerhost, peerport, fh and tls are provided. 48Defaults for peerhost, peerport and fh are provided.
49 49
50=cut 50=cut
51 51
52sub mp_server($$@) { 52sub mp_server($$@) {
53 my $cb = pop; 53 my $cb = pop;
58 58
59 $cb->(new AnyEvent::MP::Transport 59 $cb->(new AnyEvent::MP::Transport
60 fh => $fh, 60 fh => $fh,
61 peerhost => $host, 61 peerhost => $host,
62 peerport => $port, 62 peerport => $port,
63 tls => "accept",
64 @args, 63 @args,
65 ); 64 );
66 } 65 }
67} 66}
68 67
82 $cb->(new AnyEvent::MP::Transport 81 $cb->(new AnyEvent::MP::Transport
83 fh => $fh, 82 fh => $fh,
84 peername => $host, 83 peername => $host,
85 peerhost => $nhost, 84 peerhost => $nhost,
86 peerport => $nport, 85 peerport => $nport,
87 tls => "accept",
88 @args, 86 @args,
89 ); 87 );
90 } 88 }
91} 89}
92 90
105 on_eof => sub { clean-close-callback }, 103 on_eof => sub { clean-close-callback },
106 on_connect => sub { successful-connect-callback }, 104 on_connect => sub { successful-connect-callback },
107 greeting => { key => value }, 105 greeting => { key => value },
108 106
109 # tls support 107 # tls support
110 tls => "accept|connect",
111 tls_ctx => AnyEvent::TLS, 108 tls_ctx => AnyEvent::TLS,
112 peername => $peername, # for verification 109 peername => $peername, # for verification
113 ; 110 ;
114 111
115=cut 112=cut
116 113
117our @FRAMINGS = qw(json storable); # the framing types we accept and send, in order of preference 114our @FRAMINGS = qw(json storable); # the framing types we accept and send, in order of preference
118our @AUTH_SND = qw(hmac_md6_64_256); # auth types we send 115our @AUTH_SND = qw(hmac_md6_64_256); # auth types we send
119our @AUTH_RCV = (@AUTH_SND, qw(hex_secret)); # auth types we accept 116our @AUTH_RCV = (@AUTH_SND, qw(cleartext)); # auth types we accept
120 117
121#AnyEvent::Handle::register_write_type mp_record => sub { 118#AnyEvent::Handle::register_write_type mp_record => sub {
122#}; 119#};
123 120
124sub new { 121sub new {
129 $self->{queue} = []; 126 $self->{queue} = [];
130 127
131 { 128 {
132 Scalar::Util::weaken (my $self = $self); 129 Scalar::Util::weaken (my $self = $self);
133 130
134 if (exists $arg{connect}) { 131 $arg{tls_ctx_disabled} ||= {
135 $arg{tls_ctx} ||= { sslv2 => 0, sslv3 => 0, tlsv1 => 1, verify => 1 }; 132 sslv2 => 0,
133 sslv3 => 0,
134 tlsv1 => 1,
135 verify => 1,
136 cert_file => "secret.pem",
137 ca_file => "secret.pem",
138 verify_require_client_cert => 1,
136 } 139 };
137 140
138 $arg{secret} = AnyEvent::MP::Base::default_secret () 141 $arg{secret} = AnyEvent::MP::Base::default_secret ()
139 unless exists $arg{secret}; 142 unless exists $arg{secret};
140 143
141 $self->{hdl} = new AnyEvent::Handle 144 $self->{hdl} = new AnyEvent::Handle
142 fh => delete $arg{fh}, 145 fh => delete $arg{fh},
143 rbuf_max => 64 * 1024,
144 autocork => 1, 146 autocork => 1,
145 no_delay => 1, 147 no_delay => 1,
146 on_error => sub { 148 on_error => sub {
147 $self->error ($_[2]); 149 $self->error ($_[2]);
148 }, 150 },
155 if $arg{tls_ctx}; 157 if $arg{tls_ctx};
156 $greeting_kv->{provider} = "AE-$VERSION"; 158 $greeting_kv->{provider} = "AE-$VERSION";
157 $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport}; 159 $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport};
158 160
159 # send greeting 161 # send greeting
160 my $lgreeting1 = "aemp;$PROTOCOL_VERSION;$PROTOCOL_VERSION" # version, min 162 my $lgreeting1 = "aemp;$PROTOCOL_VERSION"
161 . ";$AnyEvent::MP::Base::UNIQ" 163 . ";$AnyEvent::MP::Base::UNIQ"
162 . ";$AnyEvent::MP::Base::NODE" 164 . ";$AnyEvent::MP::Base::NODE"
163 . ";" . (join ",", @AUTH_RCV) 165 . ";" . (join ",", @AUTH_RCV)
164 . ";" . (join ",", @FRAMINGS) 166 . ";" . (join ",", @FRAMINGS)
165 . (join "", map ";$_=$greeting_kv->{$_}", keys %$greeting_kv); 167 . (join "", map ";$_=$greeting_kv->{$_}", keys %$greeting_kv);
168
166 my $lgreeting2 = MIME::Base64::encode_base64 AnyEvent::MP::Base::nonce (33), ""; 169 my $lgreeting2 = MIME::Base64::encode_base64 AnyEvent::MP::Base::nonce (33), "";
167 170
168 $self->{hdl}->push_write ("$lgreeting1\012$lgreeting2\012"); 171 $self->{hdl}->push_write ("$lgreeting1\012$lgreeting2\012");
169 172
170 # expect greeting 173 # expect greeting
174 $self->{hdl}->rbuf_max (4 * 1024);
171 $self->{hdl}->push_read (line => sub { 175 $self->{hdl}->push_read (line => sub {
172 my $rgreeting1 = $_[1]; 176 my $rgreeting1 = $_[1];
173 177
174 my ($aemp, $version, $version_min, $uniq, $rnode, $auths, $framings, @kv) = split /;/, $rgreeting1; 178 my ($aemp, $version, $uniq, $rnode, $auths, $framings, @kv) = split /;/, $rgreeting1;
175 179
176 if ($aemp ne "aemp") { 180 if ($aemp ne "aemp") {
177 return $self->error ("unparsable greeting"); 181 return $self->error ("unparsable greeting");
178 } elsif ($version_min > $PROTOCOL_VERSION) { 182 } elsif ($version != $PROTOCOL_VERSION) {
179 return $self->error ("version mismatch (we: $PROTOCOL_VERSION, they: $version_min .. $version)"); 183 return $self->error ("version mismatch (we: $PROTOCOL_VERSION, they: $version)");
180 } 184 }
181 185
182 my $s_auth; 186 my $s_auth;
183 for my $auth_ (split /,/, $auths) { 187 for my $auth_ (split /,/, $auths) {
184 if (grep $auth_ eq $_, @AUTH_SND) { 188 if (grep $auth_ eq $_, @AUTH_SND) {
213 217
214 # read nonce 218 # read nonce
215 $self->{hdl}->push_read (line => sub { 219 $self->{hdl}->push_read (line => sub {
216 my $rgreeting2 = $_[1]; 220 my $rgreeting2 = $_[1];
217 221
218 if ($self->{tls_ctx} and 1 == int $self->{remote_greeting}{"tls"}) { 222 if ($self->{tls_ctx} and 1 == int $self->{remote_greeting}{tls}) {
219 $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept"; 223 $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept";
220 $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx}); 224 $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx});
221 } 225 }
222 226
223 # auth 227 # auth
224 require Digest::MD6; 228 require Digest::MD6;
225 require Digest::HMAC_MD6; 229 require Digest::HMAC_MD6;
226 230
227 my $key = Digest::MD6::md6_hex ($secret); 231 my $key = Digest::MD6::md6 ($secret);
228 my $lauth = Digest::HMAC_MD6::hmac_md6_base64 ($key, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012", 64, 256); 232 my $lauth = Digest::HMAC_MD6::hmac_md6_hex ($key, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012", 64, 256);
229 233
230 my $rauth = 234 my $rauth =
231 $s_auth eq "hmac_md6_64_256" ? Digest::HMAC_MD6::hmac_md6_base64 ($key, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012", 64, 256) 235 $s_auth eq "hmac_md6_64_256" ? Digest::HMAC_MD6::hmac_md6_hex ($key, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012", 64, 256)
232 : $s_auth eq "hex_secret" ? unpack "H*", $secret 236 : $s_auth eq "cleartext" ? unpack "H*", $secret
233 : die; 237 : die;
234 238
235 $lauth ne $rauth # echo attack? 239 $lauth ne $rauth # echo attack?
236 or return $self->error ("authentication error"); 240 or return $self->error ("authentication error");
237 241
238 $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012"); 242 $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012");
239 243
240 $self->{hdl}->rbuf_max (64); # enough for 44 reply bytes or so 244 # reasd the authentication response
241 $self->{hdl}->push_read (line => sub { 245 $self->{hdl}->push_read (line => sub {
242 my ($hdl, $rline) = @_; 246 my ($hdl, $rline) = @_;
243 247
244 my ($auth_method, $rauth2, $r_framing) = split /;/, $rline; 248 my ($auth_method, $rauth2, $r_framing) = split /;/, $rline;
245 249
252 $hdl->rbuf_max (undef); 256 $hdl->rbuf_max (undef);
253 my $queue = delete $self->{queue}; # we are connected 257 my $queue = delete $self->{queue}; # we are connected
254 258
255 $self->connected; 259 $self->connected;
256 260
261 my $src_node = $self->{node};
262
257 $hdl->push_write ($self->{s_framing} => $_) 263 $hdl->push_write ($self->{s_framing} => $_)
258 for @$queue; 264 for @$queue;
259 265
260 my $rmsg; $rmsg = sub { 266 my $rmsg; $rmsg = sub {
261 $_[0]->push_read ($r_framing => $rmsg); 267 $_[0]->push_read ($r_framing => $rmsg);
262 268
269 local $AnyEvent::MP::Base::SRCNODE = $src_node;
263 AnyEvent::MP::Base::_inject ($_[1]); 270 AnyEvent::MP::Base::_inject (@{ $_[1] });
264 }; 271 };
265 $hdl->push_read ($r_framing => $rmsg); 272 $hdl->push_read ($r_framing => $rmsg);
266 }); 273 });
267 }); 274 });
268 }); 275 });
320CR LF pair, or a single ASCII LF (recommended). 327CR LF pair, or a single ASCII LF (recommended).
321 328
322=head2 GREETING 329=head2 GREETING
323 330
324The first line contains strings separated (not ended) by C<;> 331The first line contains strings separated (not ended) by C<;>
325characters. The first seven strings are fixed by the protocol, the 332characters. The first even ixtrings are fixed by the protocol, the
326remaining strings are C<KEY=VALUE> pairs. None of them may contain C<;> 333remaining strings are C<KEY=VALUE> pairs. None of them may contain C<;>
327characters themselves. 334characters themselves.
328 335
336All the lines until after authentication must not exceed 4kb in length,
337including delimiter. Afterwards there is no limit on the packet size that
338can be received.
339
340=head3 First Greeting Line
341
329The seven fixed strings are: 342The fixed strings are:
330 343
331=over 4 344=over 4
332 345
333=item C<aemp> 346=item C<aemp>
334 347
335The constant C<aemp> to identify the protocol. 348The constant C<aemp> to identify the protocol.
336 349
337=item protocol version 350=item protocol version
338 351
339The (maximum) protocol version supported by this end, currently C<0>.
340
341=item minimum protocol version
342
343The minimum protocol version supported by this end, currently C<0>. 352The protocol version supported by this end, currently C<0>. If the
353versions don't match then no communication is possible. Minor extensions
354are supposed to be handled by addign additional key-value pairs.
344 355
345=item a token uniquely identifying the current node instance 356=item a token uniquely identifying the current node instance
346 357
347This is a string that must change between restarts. It usually contains 358This is a string that must change between restarts. It usually contains
348things like the current time, the (OS) process id or similar values, but 359things like the current time, the (OS) process id or similar values, but
366 377
367A comma-separated list of packet encoding/framign formats understood. The 378A comma-separated list of packet encoding/framign formats understood. The
368receiving side should choose the first framing format it supports for 379receiving side should choose the first framing format it supports for
369sending packets (which might be different from the format it has to accept). 380sending packets (which might be different from the format it has to accept).
370 381
371=cut 382=back
372 383
373The remaining arguments are C<KEY=VALUE> pairs. The following key-value 384The remaining arguments are C<KEY=VALUE> pairs. The following key-value
374pairs are known at this time: 385pairs are known at this time:
375 386
376=over 4 387=over 4
389 400
390Indicates that the other side supports TLS (version should be 1.0) and 401Indicates that the other side supports TLS (version should be 1.0) and
391wishes to do a TLS handshake. 402wishes to do a TLS handshake.
392 403
393=back 404=back
405
406=head3 Second Greeting Line
394 407
395After this greeting line there will be a second line containing a 408After this greeting line there will be a second line containing a
396cryptographic nonce, i.e. random data of high quality. To keep the 409cryptographic nonce, i.e. random data of high quality. To keep the
397protocol text-only, these are usually 32 base64-encoded octets, but 410protocol text-only, these are usually 32 base64-encoded octets, but
398it could be anything that doesn't contain any ASCII CR or ASCII LF 411it could be anything that doesn't contain any ASCII CR or ASCII LF
399characters. 412characters.
400 413
414I<< The two nonces B<must> be different, and an aemp implementation
415B<must> check and fail when they are identical >>.
416
401Example of the two lines of greeting: 417Example of the two lines of greeting:
402 418
403 aemp;0;0;e7d.4a76f48f;10.0.0.1:4040;hmac_md6_64_256,hex_secret;json,storable;provider=AE-0.0;peeraddr=127.0.0.1:1235 419 aemp;0;fec.4a7720fc;127.0.0.1:1235,[::1]:1235;hmac_md6_64_256;json,storable;provider=AE-0.0
404 XntegV2Guvss0qNn7phCPnoU87xqxV+4Mqm/5y4iQm6a 420 p/I122ql7kJR8lumW3lXlXCeBnyDAvz8NQo3x5IFowE4
405 421
406=head2 TLS handshake 422=head2 TLS handshake
407 423
408If, after the handshake, both sides indicate interest in TLS, then the 424I<< If, after the handshake, both sides indicate interest in TLS, then the
409connection I<must> use TLS, or fail. 425connection B<must> use TLS, or fail.>>
410 426
411Both sides compare their nonces, and the side who sent the lower nonce 427Both sides compare their nonces, and the side who sent the lower nonce
412value ("string" comparison on the raw octet values) becomes the client, 428value ("string" comparison on the raw octet values) becomes the client,
413and the one with the higher nonce the server. 429and the one with the higher nonce the server.
414 430
425 441
426=item the authentication method chosen 442=item the authentication method chosen
427 443
428This must be one of the methods offered by the other side in the greeting. 444This must be one of the methods offered by the other side in the greeting.
429 445
446The currently supported authentication methods are:
447
448=over 4
449
450=item cleartext
451
452This is simply the shared secret, lowercase-hex-encoded. This method is of
453course very insecure, unless TLS is used, which is why this module will
454accept, but not generate, cleartext auth replies.
455
456=item hmac_md6_64_256
457
458This method uses an MD6 HMAC with 64 bit blocksize and 256 bit hash. First, the shared secret
459is hashed with MD6:
460
461 key = MD6 (secret)
462
463This secret is then used to generate the "local auth reply", by taking
464the two local greeting lines and the two remote greeting lines (without
465line endings), appending \012 to all of them, concatenating them and
466calculating the MD6 HMAC with the key.
467
468 lauth = HMAC_MD6 key, "lgreeting1\012lgreeting2\012rgreeting1\012rgreeting2\012"
469
470This authentication token is then lowercase-hex-encoded and sent to the
471other side.
472
473Then the remote auth reply is generated using the same method, but local
474and remote greeting lines swapped:
475
476 rauth = HMAC_MD6 key, "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012"
477
478This is the token that is expected from the other side.
479
480=back
481
430=item the authentication data 482=item the authentication data
431 483
432The authentication data itself, usually base64 or hex-encoded data. 484The authentication data itself, usually base64 or hex-encoded data, see
485above.
433 486
434=item the framing protocol chosen 487=item the framing protocol chosen
435 488
436This must be one of the framing protocols offered by the other side in the 489This must be one of the framing protocols offered by the other side in the
437greeting. Each side must accept the choice of the other side. 490greeting. Each side must accept the choice of the other side.
438 491
439=back 492=back
440 493
494Example:
495
496 hmac_md6_64_256;363d5175df38bd9eaddd3f6ca18aa1c0c4aa22f0da245ac638d048398c26b8d3;json
497
441=head2 DATA PHASE 498=head2 DATA PHASE
442 499
443After this, packets get exchanged using the chosen framing protocol. It is 500After this, packets get exchanged using the chosen framing protocol. It is
444quite possible that both sides use a different framing protocol. 501quite possible that both sides use a different framing protocol.
445 502

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines