#define MISC_EPONG 4u /* Encrypted ping response */
#define MISC_GREET 5u /* A greeting from a NATed peer */
#define MISC_BYE 6u /* Departure notification */
+#define MISC_WGT 7u /* You sent message: who are you? */
+
+#define WGTLEN 17u
/* --- Symmetric encryption and keysets --- *
*
struct tunnel_node *next;
const tunnel_ops *tops;
} *tunnels, **tunnels_tail = &tunnels;
+static ratelim wgt_limit;
const tunnel_ops *dflttun;
/*----- Main code ---------------------------------------------------------*/
{
peer *p, *q;
int err = KSERR_DECRYPT;
+ buf b;
/* --- If we have a match on the source address then try that first --- */
searched:
if (!p) {
- if (!q)
+ if (!q) {
a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END);
- else {
+ if (!ratelim_withdraw(&wgt_limit, 1)) {
+ buf_init(&b, buf_t, sizeof(buf_t));
+ buf_putbyte(&b, MSG_MISC | MISC_WGT);
+ if (n > WGTLEN) n = WGTLEN;
+ buf_put(&b, buf_i, n);
+ T( trace(T_PEER, "peer: sending who-goes-there message"); )
+ assert(BOK(&b)); p_txaddr(a, BBASE(&b), BLEN(&b));
+ }
+ } else {
a_warn("PEER", "?PEER", p, "decrypt-failed",
"error-code", "%d", err, A_END);
p_rxupdstats(q, n);
ssize_t n;
int ch;
buf b, bb;
+ const octet *q;
+ unsigned i;
+ time_t now;
#ifndef NTRACE
int ix = -1;
char name[NI_MAXHOST], svc[NI_MAXSERV];
buf_flip(&bb);
p_encrypt(p, MSG_MISC | MISC_EPONG, &bb,
p_txstart(p, MSG_MISC | MISC_EPONG));
- p_txend(p, 0);
+ p_txend(p, TXF_WGT);
}
break;
case MISC_EPONG:
p_destroy(p, 0);
}
break;
+ case MISC_WGT:
+ if (!p) goto unexp;
+ if (!(p->spec.f&PSF_EPHEM))
+ { a_warn("PEER", "?PEER", p, "unexpected-wgt", A_END); break; }
+ n = BLEFT(&b); if (n > WGTLEN) n = WGTLEN;
+ now = time(0);
+ q = buf_get(&b, n); assert(q);
+ for (i = 0; i < NWGT; i++) {
+ if (p->wgt[i].when != (time_t)-1 &&
+ now - p->wgt[i].when <= T_WGT &&
+ p->wgt[i].sz == n &&
+ MEMCMP(p->wgt[i].msg, ==, q, n))
+ goto found_wgt;
+ }
+ a_warn("PEER", "?PEER", p, "unrecognized-wgt", A_END);
+ break;
+ found_wgt:
+ if (p->spec.knock) {
+ T( trace(T_PEER, "peer: who-goes-there from peer: knocking"); )
+ kx_start(&p->kx, 0);
+ } else {
+ T( trace(T_PEER, "peer: who-goes-there from peer: notifying"); )
+ a_notify("WGT", "?PEER", p, A_END);
+ }
+ break;
}
break;
default:
void p_txend(peer *p, unsigned f)
{
+ size_t n;
+
if (p_dotxend(p)) {
+ if ((f&TXF_WGT) && (p->spec.f&PSF_EPHEM)) {
+ n = BLEN(&p->b); if (n > WGTLEN) n = WGTLEN;
+ memcpy(p->wgt[p->wgtix].msg, BBASE(&p->b), n);
+ p->wgt[p->wgtix].sz = n;
+ p->wgt[p->wgtix].when = time(0);
+ p->wgtix++; if (p->wgtix >= NWGT) p->wgtix = 0;
+ }
if (p->spec.t_ka) {
sel_rmtimer(&p->tka);
p_setkatimer(p);
p_encrypt(p, MSG_MISC | MISC_EPING, &bb, b);
if (!BOK(b))
return (-1);
- p_txend(p, 0);
+ p_txend(p, TXF_WGT);
break;
default:
abort();
if (BOK(bb) && BLEN(bb)) {
p->st.n_ipout++;
p->st.sz_ipout += BLEN(bb);
- p_txend(p, 0);
+ p_txend(p, TXF_WGT);
}
}
{
sym_create(&byname);
am_create(&byaddr);
+ ratelim_init(&wgt_limit, 5, 100);
}
/* --- @p_addtun@ --- *
peer *p = CREATE(peer);
const tunnel_ops *tops = spec->tops;
int fd;
- unsigned f;
+ unsigned f, i;
p->byname = sym_find(&byname, spec->name, -1, sizeof(peer_byname), &f);
if (f) goto tidy_0;
/* Couldn't tell anyone before */
}
if (p->spec.f & PSF_MOBILE) nmobile++;
+ for (i = 0; i < NWGT; i++) {
+ p->wgt[i].sz = 0;
+ p->wgt[i].when = (time_t)-1;
+ }
+ p->wgtix = 0;
return (p);
tidy_4:
COMMS_EPING([alice], [alice], [bob], [bob])
COMMS_SLIP([alice], [alice], [bob], [bob])
+
+ AT_CHECK([TRIPECTL -dalice KILL -quiet bob])
+ AT_CHECK([TRIPECTL -dbob FORCEKX -quiet alice])
+ echo "WARN PEER - unexpected-source INET 127.0.0.1 $bob_from_alice" >>alice/expected-server-output
+ WAIT_KNOCK([alice], [bob], [
+ AT_CHECK([TRIPECTL -dbob EPING alice],, [ping-timeout[]nl])
+ ])
+ AWAIT_KXDONE([alice], [alice], [bob], [bob], [
+ AT_CHECK([TRIPECTL -dalice ADD -ephemeral bob INET 127.0.0.1 $bob_from_alice])
+ ])
+ COMMS_EPING([alice], [alice], [bob], [bob])
+ COMMS_SLIP([alice], [alice], [bob], [bob])
])
WITH_MITM([alice], [=new_bob_from_alice], [bob], [$alice_from_bob], [
An administration client issued a notification using the
.B NOTIFY
command.
+.SP
+.BI "WGT " peer
+A who-goes-there message was received from an ephemeral
+.IR peer ,
+implying that it has forgotten about us. If a service knows how to
+inform the peer of our existence, it should do so. This notification is
+not sent for peers which have a
+.B knock
+string configured, because the server automatically tries knocking again
+in this case.
.
.\"--------------------------------------------------------------------------
.SH "WARNINGS"
match any outstanding ping. Maybe it was delayed for longer than the
server was willing to wait, or maybe the peer has gone mad; or maybe
there are bad people trying to confuse you.
+.SP
+.BI "PEER " peer " unexpected-wgt"
+A `who-goes-there' message from received from
+.IR peer ,
+but the peer isn't ephemeral.
+.SP
+.BI "PEER " peer " unrecognized-wgt"
+A `who-goes-there' message from received from
+.IR peer ,
+but it doesn't quote the start of a message which we recently sent to
+it.
.SS "PRIVSEP warnings"
These indicate problems with the privilege-separation helper process.
(The server tries to drop its privileges when it starts up, leaving a
#define T_WOBBLE (1.0/3.0) /* Relative timer randomness */
+#define T_WGT 5 /* Age for who-goes-there */
+
/* --- Other things --- */
#define PKBUFSZ 65536
stats st; /* Statistics */
keyexch kx; /* Key exchange protocol block */
sel_timer tka; /* Timer for keepalives */
+#define NWGT 16
+ struct {
+ octet msg[WGTLEN]; /* Message prefix */
+ unsigned sz; /* Length of prefix */
+ time_t when; /* Time it was transmitted */
+ } wgt[NWGT]; /* Recently sent messages */
+ unsigned wgtix; /* Next index to transmit */
} peer;
typedef struct peer_iter { sym_iter i; } peer_iter;
* Use: Sends a packet to the peer.
*/
+#define TXF_WGT 1u /* Include in who-goes-there table */
extern void p_txend(peer */*p*/, unsigned /*f*/);
/* --- @p_pingsend@ --- *
try: p = Peer(rest[0])
except KeyError: pass
else: disownpeer(p, *rest[1:])
+ elif code == 'WGT':
+ try: p = pinger.find(rest[0])
+ except KeyError: pass
+ else: p.reconnect()
elif code == 'GREET':
chal = rest[0]
try: cr = chalmap[chal]
[5] = { label = "MISC_GREET", info = "greeting",
dissect = { dissect_misc_payload } },
[6] = { label = "MISC_BYE", info = "disconnect notification",
- dissect = { dissect_misc_ciphertext } },
+ dissect = { dissect_misc_ciphertext },
+ [7] = { label = "MISC_WGT", info = "unexpected-sender notification",
+ dissect = { dissect_misc_payload } },
}
}
}