From 01c2190311b3eab8e861014d57ddca6160998e69 Mon Sep 17 00:00:00 2001 Message-Id: <01c2190311b3eab8e861014d57ddca6160998e69.1714150549.git.mdw@distorted.org.uk> From: Mark Wooding Date: Mon, 7 May 2012 14:37:05 +0100 Subject: [PATCH] server/peer.c, server/tests.at: Handle NAT swapping over peer addresses. Organization: Straylight/Edgeware From: Mark Wooding Previously, we'd notice when a mobile peer switched address (e.g., due to NAT) to one that wasn't currently known; but it seems that some particularly awful NAT boxes will actually swap over the addresses assigned to two peers on the wrong side of it. The static hub peer will see this as a bunch of decryption failures but not do anything about it. Eventually the mobile peers will notice a ping timeout and reconnect, but this can take a while. So, when we get a decryption failure from a mobile peer, see whether any other mobile peers are interested in it. --- server/peer.c | 24 ++++++++++------ server/tests.at | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 11 deletions(-) diff --git a/server/peer.c b/server/peer.c index 02fceed5..308ab1d1 100644 --- a/server/peer.c +++ b/server/peer.c @@ -215,20 +215,21 @@ static int p_decrypt(peer **pp, addr *a, size_t n, /* --- See whether any mobile peer is interested --- */ - FOREACH_PEER(pp, { - if (pp == q || !(pp->spec.f & PSF_MOBILE)) continue; - if ((err = ksl_decrypt(&pp->ks, ty, bin, bout)) == KSERR_DECRYPT) { + p = 0; + FOREACH_PEER(qq, { + if (qq == q || !(qq->spec.f & PSF_MOBILE)) continue; + if ((err = ksl_decrypt(&qq->ks, ty, bin, bout)) == KSERR_DECRYPT) { T( trace(T_PEER, "peer: peer `%s' failed to decrypt", - p_name(pp)); ) + p_name(qq)); ) continue; } else { - p = pp; + p = qq; IF_TRACING(T_PEER, { if (!err) - trace(T_PEER, "peer: peer `%s' reports success", p_name(pp)); + trace(T_PEER, "peer: peer `%s' reports success", p_name(qq)); else { trace(T_PEER, "peer: peer `%s' reports decryption error %d", - p_name(pp), err); + p_name(qq), err); } }) break; @@ -239,7 +240,13 @@ static int p_decrypt(peer **pp, addr *a, size_t n, searched: if (!p) { - a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END); + if (!q) + a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END); + else { + a_warn("PEER", "?PEER", p, "decrypt-failed", + "error-code", "%d", err, A_END); + p_rxupdstats(q, n); + } return (-1); } @@ -252,6 +259,7 @@ searched: */ if (!err) { + *pp = p; if (!q) { T( trace(T_PEER, "peer: updating address for `%s'", p_name(p)); ) pa = am_find(&byaddr, a, sizeof(peer_byaddr), &f); assert(!f); diff --git a/server/tests.at b/server/tests.at index c490ff2b..ab64c538 100644 --- a/server/tests.at +++ b/server/tests.at @@ -38,6 +38,8 @@ m4_define([TRIPE], $abs_top_builddir/server/tripe -F -d. -aadmin -p0 -b127.0.0.1 -talice]) m4_define([TRIPECTL], [$abs_top_builddir/client/tripectl -d. -aadmin]) m4_define([USLIP], [$abs_top_builddir/uslip/tripe-uslip]) +m4_define([PKSTREAM], + [$abs_top_builddir/pkstream/pkstream -b127.0.0.1 -p127.0.0.1]) ## Sequences. (These are used for testing the replay protection machinery.) m4_define([R32], [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 dnl @@ -228,13 +230,15 @@ m4_define([AWAIT_KXDONE], [ TRIPECTL -d$4 WARN test POP ]) -## ESTABLISH(adir, aname, aopts, bdir, bname, bopts) +## ESTABLISH(adir, aname, aopts, bdir, bname, bopts, [aport], [bport]) m4_define([ESTABLISH], [ ## Set up the establishment. AWAIT_KXDONE([$1], [$2], [$4], [$5], [ - AT_CHECK([TRIPECTL -d$1 ADD -cork $6 $5 INET 127.0.0.1 $(cat $4/port)]) - AT_CHECK([TRIPECTL -d$4 ADD $3 $2 INET 127.0.0.1 $(cat $1/port)]) + AT_CHECK([TRIPECTL -d$1 ADD -cork $6 $5 INET 127.0.0.1 \ + m4_if([$8], [], [$(cat $4/port)], [$8])]) + AT_CHECK([TRIPECTL -d$4 ADD $3 $2 INET 127.0.0.1 \ + m4_if([$7], [], [$(cat $1/port)], [$7])]) ]) ## Check transport pinging. @@ -354,6 +358,71 @@ WITH_2TRIPES([alice], [bob], [-nslip], [-talice], [-tbob], [ AT_CLEANUP +###-------------------------------------------------------------------------- +### Mobile peer tracking. + +AT_SETUP([peer tracking]) +AT_KEYWORDS([mobile]) +export TRIPE_SLIPIF=USLIP + +for p in alice bob carol; do (mkdir $p; cd $p; SETUPDIR([alpha])); done + +## WITH_PKSTREAM(adir, aport, bdir, bport, body) +m4_define([WITH_PKSTREAM], [ + echo >&2 "pkstream: $1 <--> :$2 <-pkstream-> :$4 <--> $3" + PKSTREAM -l$4 127.0.0.1:$4 127.0.0.1:$(cat $3/port)& pkstream_$3_$1=$! + sleep 1 + PKSTREAM -c127.0.0.1:$4 127.0.0.1:$2 127.0.0.1:$(cat $1/port)& + pkstream_$1_$3=$! + set +x + $5 + kill $pkstream_$3_$1 $pkstream_$1_$3 +]) + +WITH_3TRIPES([alice], [bob], [carol], [-nslip], + [-talice], [-tbob], [-tcarol], [ + + ## We need an indirection layer between the two peers so that we can + ## simulate the effects of NAT remapping. The nearest thing we have to + ## this is pkstream, so we may as well use that. + ## + ## alice <--> :5311 <-pkstream-> :5312 <--> bob + ## alice <--> :5321 <-pkstream-> :5322 <--> carol + + WITH_PKSTREAM([alice], [5311], [bob], [5312], [ + ESTABLISH([alice], [alice], [], [bob], [bob], [-mobile], [5312], [5311]) + ]) + + WITH_PKSTREAM([alice], [5319], [bob], [5312], [ + COMMS_EPING([bob], [bob], [alice], [alice]) + COMMS_SLIP([bob], [bob], [alice], [alice]) + ]) + + WITH_PKSTREAM([alice], [5321], [carol], [5322], [ + ESTABLISH([alice], [alice], [], [carol], [carol], [-mobile], + [5322], [5321]) + ]) + + WITH_PKSTREAM([alice], [5311], [bob], [5312], [ + WITH_PKSTREAM([alice], [5321], [carol], [5322], [ + COMMS_EPING([bob], [bob], [alice], [alice]) + COMMS_EPING([carol], [carol], [alice], [alice]) + COMMS_SLIP([bob], [bob], [alice], [alice]) + COMMS_SLIP([carol], [carol], [alice], [alice]) + ])]) + + WITH_PKSTREAM([alice], [5321], [bob], [5312], [ + WITH_PKSTREAM([alice], [5311], [carol], [5322], [ + COMMS_EPING([bob], [bob], [alice], [alice]) + COMMS_EPING([carol], [carol], [alice], [alice]) + COMMS_SLIP([bob], [bob], [alice], [alice]) + COMMS_SLIP([carol], [carol], [alice], [alice]) + ])]) + wait +]) + +AT_CLEANUP + ###-------------------------------------------------------------------------- ### Services. -- [mdw]