X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/88622d1dc9b1c03e95552817151047e574b312d4..61682d3405e6b7c72ec8295fec1467333e336b65:/server/peer.c diff --git a/server/peer.c b/server/peer.c index a62b20a8..308ab1d1 100644 --- a/server/peer.c +++ b/server/peer.c @@ -188,45 +188,79 @@ static int p_encrypt(peer *p, int ty, buf *bin, buf *bout) static int p_decrypt(peer **pp, addr *a, size_t n, int ty, buf *bin, buf *bout) { - peer *p; - peer_byaddr *pa; + peer *p, *q; + peer_byaddr *pa, *qa; int err = KSERR_DECRYPT; unsigned f; - if (*pp) { - p = *pp; + /* --- If we have a match on the source address then try that first --- */ + + q = *pp; + if (q) { T( trace(T_PEER, "peer: decrypting packet from known peer `%s'", - p_name(p)); ) - err = ksl_decrypt(&p->ks, ty, bin, bout); - } else { + p_name(q)); ) + if ((err = ksl_decrypt(&q->ks, ty, bin, bout)) != KSERR_DECRYPT || + !(q->spec.f & PSF_MOBILE) || nmobile == 1) { + p = q; + goto match; + } + T( trace(T_PEER, "peer: failed to decrypt: try other mobile peers...", + p_name(q)); ) + } else if (nmobile) + T( trace(T_PEER, "peer: unknown source: trying mobile peers..."); ) + else { p = 0; - if (nmobile) { - T( trace(T_PEER, "peer: unknown source: trying mobile peers..."); ) - FOREACH_PEER(q, { - if (!(q->spec.f & PSF_MOBILE)) continue; - if ((err = ksl_decrypt(&q->ks, ty, bin, bout)) == KSERR_DECRYPT) { - T( trace(T_PEER, "peer: peer `%s' failed to decrypt", - p_name(q)); ) - continue; - } else { - p = *pp = q; - IF_TRACING(T_PEER, { - if (!err) - trace(T_PEER, "peer: peer `%s' reports success", p_name(p)); - else { - trace(T_PEER, "peer: peer `%s' reports decryption error %d", - p_name(p), err); - } - }) - break; + goto searched; + } + + /* --- See whether any mobile peer is interested --- */ + + 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(qq)); ) + continue; + } else { + p = qq; + IF_TRACING(T_PEER, { + if (!err) + trace(T_PEER, "peer: peer `%s' reports success", p_name(qq)); + else { + trace(T_PEER, "peer: peer `%s' reports decryption error %d", + p_name(qq), err); } - }); + }) + break; } - if (!p) { + }); + + /* --- We've searched the mobile peers --- */ + +searched: + if (!p) { + if (!q) a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END); - return (-1); + else { + a_warn("PEER", "?PEER", p, "decrypt-failed", + "error-code", "%d", err, A_END); + p_rxupdstats(q, n); } - if (!err) { + return (-1); + } + + /* --- We found one that accepted, so update the peer's address --- * + * + * If we had an initial guess of which peer this packet came from -- i.e., + * @q@ is not null -- then swap the addresses over. This doesn't leave the + * evicted peer in an especially good state, but it ought to get sorted out + * soon enough. + */ + + 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); am_remove(&byaddr, p->byaddr); @@ -234,8 +268,18 @@ static int p_decrypt(peer **pp, addr *a, size_t n, pa->p = p; p->spec.sa = *a; a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); + } else { + T( trace(T_PEER, "peer: swapping addresses for `%s' and `%s'", + p_name(p), p_name(q)); ) + pa = p->byaddr; qa = q->byaddr; + pa->p = q; q->byaddr = pa; q->spec.sa = p->spec.sa; + qa->p = p; p->byaddr = qa; p->spec.sa = *a; + a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); + a_notify("NEWADDR", "?PEER", q, "?ADDR", &q->spec.sa, A_END); } } + +match: p_rxupdstats(p, n); if (err) { if (p) p->st.n_reject++;