{ 't', T_TUNNEL, "tunnel events" },
{ 'r', T_PEER, "peer events" },
{ 'a', T_ADMIN, "admin interface" },
- { 'p', T_PACKET, "packet contents" },
- { 'c', T_CRYPTO, "crypto details" },
{ 's', T_KEYSET, "symmetric keyset management" },
{ 'x', T_KEYEXCH, "key exchange" },
{ 'm', T_KEYMGMT, "key management" },
+ { 'l', T_CHAL, "challenge management" },
+ { 'p', T_PACKET, "packet contents" },
+ { 'c', T_CRYPTO, "crypto details" },
{ 'A', T_ALL, "all of the above" },
{ 0, 0, 0 }
};
return (t);
}
+/* --- @a_findpeer@ --- *
+ *
+ * Arguments: @admin *a@ = admin connection
+ * @const char *pn@ = peer name
+ *
+ * Returns: The peer, or null if not there.
+ *
+ * Use: Finds a peer, reporting an error if it failed.
+ */
+
+static peer *a_findpeer(admin *a, const char *pn)
+{
+ peer *p;
+
+ if ((p = p_find(pn)) == 0)
+ a_fail(a, "unknown-peer %s", pn);
+ return (p);
+}
+
/*----- Backgrounded operations -------------------------------------------*/
#define BGTAG(bg) \
if (tag) a_write(a, "DETACH", tag, 0);
}
-/*----- Adding peers ------------------------------------------------------*/
+/*----- Name resolution operations ----------------------------------------*/
-/* --- @a_addfree@ --- *
+/* --- @a_resolved@ --- *
*
- * Arguments: @admin_addop *add@ = operation block
+ * Arguments: @struct hostent *h@ = pointer to resolved hostname
+ * @void *v@ = pointer to resolver operation
*
* Returns: ---
*
- * Use: Frees an add operation.
+ * Use: Handles a completed name resolution.
*/
-static void a_addfree(admin_addop *add)
+static void a_resolved(struct hostent *h, void *v)
{
- T( trace(T_ADMIN, "admin: free add op %s", BGTAG(add)); )
- if (add->peer.name) xfree(add->peer.name);
- if (add->paddr) xfree(add->paddr);
-}
+ admin_resop *r = v;
+
+ T( trace(T_ADMIN, "admin: resop %s resolved", BGTAG(r)); )
+ TIMER;
+ if (!h) {
+ a_bgfail(&r->bg, "resolve-error %s", r->addr);
+ r->func(r, ARES_FAIL);
+ } else {
+ memcpy(&r->sa.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
+ r->func(r, ARES_OK);
+ }
+ sel_rmtimer(&r->t);
+ xfree(r->addr);
+ a_bgrelease(&r->bg);
+}
-/* --- @a_addcancel@ --- *
+/* --- @a_restimer@ --- *
*
- * Arguments: @admin_bgop *bg@ = background operation
+ * Arguments: @struct timeval *tv@ = timer
+ * @void *v@ = pointer to resolver operation
*
* Returns: ---
*
- * Use: Cancels an add operation.
+ * Use: Times out a resolver.
*/
-static void a_addcancel(admin_bgop *bg)
+static void a_restimer(struct timeval *tv, void *v)
{
- admin_addop *add = (admin_addop *)bg;
-
- T( trace(T_ADMIN, "admin: cancel add op %s", BGTAG(add)); )
- sel_rmtimer(&add->t);
- bres_abort(&add->r);
- a_addfree(add);
+ admin_resop *r = v;
+
+ T( trace(T_ADMIN, "admin: resop %s timeout", BGTAG(r)); )
+ a_bgfail(&r->bg, "resolver-timeout %s\n", r->addr);
+ r->func(r, ARES_FAIL);
+ bres_abort(&r->r);
+ xfree(r->addr);
+ a_bgrelease(&r->bg);
}
-/* --- @a_doadd@ --- *
+/* --- @a_rescancel@ --- *
*
- * Arguments: @admin_addop *add@ = operation block
+ * Arguments: @admin_bgop *bg@ = background operation
*
* Returns: ---
*
- * Use: Does the peer add thing.
+ * Use: Cancels an add operation.
*/
-static void a_doadd(admin_addop *add)
+static void a_rescancel(admin_bgop *bg)
{
- if (p_find(add->peer.name))
- a_bgfail(&add->bg, "peer-exists %s", add->peer.name);
- else if (!p_create(&add->peer))
- a_bgfail(&add->bg, "peer-create-fail %s", add->peer.name);
- else
- a_bgok(&add->bg);
+ admin_resop *r = (admin_resop *)bg;
+
+ T( trace(T_ADMIN, "admin: cancel resop %s", BGTAG(r)); )
+ r->func(r, ARES_FAIL);
+ sel_rmtimer(&r->t);
+ xfree(r->addr);
+ bres_abort(&r->r);
}
-
-/* --- @a_addresolve@ --- *
+
+/* --- @a_resolve@ --- *
*
- * Arguments: @struct hostent *h@ = pointer to resolved hostname
- * @void *v@ = pointer to add operation
+ * Arguments: @admin *a@ = administration connection
+ * @admin_resop *r@ = resolver operation to run
+ * @const char *tag@ = background operation tag
+ * @void (*func)(struct admin_resop *, int@ = handler function
+ * @unsigned ac@ = number of remaining arguments
+ * @char *av[]@ = pointer to remaining arguments
*
* Returns: ---
*
- * Use: Handles a completed name resolution.
+ * Use: Cranks up a resolver job.
*/
-static void a_addresolve(struct hostent *h, void *v)
+static void a_resolve(admin *a, admin_resop *r, const char *tag,
+ void (*func)(struct admin_resop *, int),
+ unsigned ac, char *av[])
{
- admin_addop *add = v;
+ struct timeval tv;
+ unsigned long pt;
+ char *p;
+ int i = 0;
- T( trace(T_ADMIN, "admin: add op %s resolved", BGTAG(add)); )
- TIMER;
- if (!h)
- a_bgfail(&add->bg, "resolve-error %s", add->paddr);
- else {
- memcpy(&add->peer.sa.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
- a_doadd(add);
+ /* --- Fill in the easy bits of address --- */
+
+ r->addr = 0;
+ r->func = func;
+ if (mystrieq(av[i], "inet")) i++;
+ if (ac - i != 2) {
+ a_fail(a, "bad-addr-syntax [inet] ADDRESS PORT");
+ goto fail;
+ }
+ r->sa.sin.sin_family = AF_INET;
+ r->sasz = sizeof(r->sa.sin);
+ r->addr = xstrdup(av[i]);
+ pt = strtoul(av[i + 1], &p, 0);
+ if (*p) {
+ struct servent *s = getservbyname(av[i + 1], "udp");
+ if (!s) {
+ a_fail(a, "unknown-service %s", av[i + 1]);
+ goto fail;
+ }
+ pt = ntohs(s->s_port);
}
- sel_rmtimer(&add->t);
- a_addfree(add);
- a_bgrelease(&add->bg);
+ if (pt == 0 || pt >= 65536) {
+ a_fail(a, "invalid-port %lu", pt);
+ goto fail;
+ }
+ r->sa.sin.sin_port = htons(pt);
+
+ /* --- Report backgrounding --- *
+ *
+ * Do this for consistency of interface, even if we're going to get the
+ * answer straight away.
+ */
+
+ a_bgadd(a, &r->bg, tag, a_rescancel);
+ T( trace(T_ADMIN, "admin: %u, resop %s, hostname `%s'",
+ a->seq, BGTAG(r), r->addr); )
+
+ /* --- If the name is numeric, do it the easy way --- */
+
+ if (inet_aton(av[i], &r->sa.sin.sin_addr)) {
+ T( trace(T_ADMIN, "admin: resop %s done the easy way", BGTAG(r)); )
+ func(r, ARES_OK);
+ xfree(r->addr);
+ a_bgrelease(&r->bg);
+ return;
+ }
+
+ /* --- Store everything for later and crank up the resolver --- */
+
+ gettimeofday(&tv, 0);
+ tv.tv_sec += T_RESOLVE;
+ sel_addtimer(&sel, &r->t, &tv, a_restimer, r);
+ bres_byname(&r->r, r->addr, a_resolved, r);
+ return;
+
+fail:
+ func(r, ARES_FAIL);
+ if (r->addr) xfree(r->addr);
+ xfree(r);
}
-/* --- @a_addtimer@ --- *
+/*----- Adding peers ------------------------------------------------------*/
+
+/* --- @a_doadd@ --- *
*
- * Arguments: @struct timeval *tv@ = timer
- * @void *v@ = pointer to add operation
+ * Arguments: @admin_resop *r@ = resolver operation
+ * @int rc@ = how it worked
*
* Returns: ---
*
- * Use: Times out a resolver.
+ * Use: Handles a completed resolution.
*/
-static void a_addtimer(struct timeval *tv, void *v)
+static void a_doadd(admin_resop *r, int rc)
{
- admin_addop *add = v;
+ admin_addop *add = (admin_addop *)r;
+
+ T( trace(T_ADMIN, "admin: done add op %s", BGTAG(add)); )
+
+ if (rc == ARES_OK) {
+ add->peer.sasz = add->r.sasz;
+ add->peer.sa = add->r.sa;
+ if (p_find(add->peer.name))
+ a_bgfail(&add->r.bg, "peer-exists %s", add->peer.name);
+ else if (!p_create(&add->peer))
+ a_bgfail(&add->r.bg, "peer-create-fail %s", add->peer.name);
+ else
+ a_bgok(&add->r.bg);
+ }
- T( trace(T_ADMIN, "admin: add op %s timeout", BGTAG(add)); )
- a_bgfail(&add->bg, "resolver-timeout %s\n", add->paddr);
- bres_abort(&add->r);
- a_addfree(add);
- a_bgrelease(&add->bg);
+ xfree(add->peer.name);
}
/* --- @acmd_add@ --- *
static void acmd_add(admin *a, unsigned ac, char *av[])
{
- unsigned long pt;
- struct timeval tv;
unsigned i, j;
- char *p;
const char *tag = 0;
admin_addop *add = 0;
- /* --- Make sure someone's not got there already --- */
-
- if (p_find(av[0])) {
- a_fail(a, "peer-exists %s", av[0]);
- goto fail;
- }
-
/* --- Set stuff up --- */
add = xmalloc(sizeof(*add));
add->peer.name = xstrdup(av[0]);
add->peer.t_ka = 0;
add->peer.tops = tun_default;
- add->paddr = 0;
+
+ /* --- Make sure someone's not got there already --- */
+
+ if (p_find(av[0])) {
+ a_fail(a, "peer-exists %s", av[0]);
+ goto fail;
+ }
/* --- Parse options --- */
for (j = 0;; j++) {
if (!tunnels[j]) {
a_fail(a, "unknown-tunnel %s", av[i]);
- return;
+ goto fail;
}
if (mystrieq(av[i], tunnels[j]->name)) {
add->peer.tops = tunnels[j];
if (!av[++i]) goto bad_syntax;
if ((t = a_parsetime(av[i])) < 0) {
a_fail(a, "bad-time-spec %s", av[i]);
- return;
+ goto fail;
}
add->peer.t_ka = t;
} else if (mystrieq(av[i], "--")) {
i++;
}
- /* --- Fill in the easy bits of address --- */
-
- if (mystrieq(av[i], "inet")) i++;
- if (ac - i != 2) {
- a_fail(a, "bad-syntax -- add PEER [OPTIONS] [inet] ADDRESS PORT");
- goto fail;
- }
- add->peer.sa.sin.sin_family = AF_INET;
- add->peer.sasz = sizeof(add->peer.sa.sin);
- add->paddr = xstrdup(av[i]);
- pt = strtoul(av[i + 1], &p, 0);
- if (*p) {
- struct servent *s = getservbyname(av[i + 1], "udp");
- if (!s) {
- a_fail(a, "unknown-service %s", av[i + 1]);
- goto fail;
- }
- pt = ntohs(s->s_port);
- }
- if (pt == 0 || pt >= 65536) {
- a_fail(a, "invalid-port %lu", pt);
- goto fail;
- }
- add->peer.sa.sin.sin_port = htons(pt);
-
- /* --- Report backgrounding --- *
- *
- * Do this for consistency of interface, even if we're going to get the
- * answer straight away.
- */
+ /* --- Crank up the resolver --- */
- a_bgadd(a, &add->bg, tag, a_addcancel);
- T( trace(T_ADMIN, "admin: %u, add op %s resolving hostname `%s'",
- a->seq, BGTAG(add), add->paddr); )
-
- /* --- If the name is numeric, do it the easy way --- */
-
- if (inet_aton(av[i], &add->peer.sa.sin.sin_addr)) {
- T( trace(T_ADMIN, "admin: add op %s done the easy way", BGTAG(add)); )
- a_doadd(add);
- a_addfree(add);
- a_bgrelease(&add->bg);
- return;
- }
-
- /* --- Store everything for later and crank up the resolver --- */
-
- gettimeofday(&tv, 0);
- tv.tv_sec += T_RESOLVE;
- sel_addtimer(&sel, &add->t, &tv, a_addtimer, add);
- bres_byname(&add->r, add->paddr, a_addresolve, add);
+ a_resolve(a, &add->r, tag, a_doadd, ac - i, av + i);
return;
+ /* --- Clearing up --- */
+
bad_syntax:
a_fail(a, "bad-syntax -- add PEER [OPTIONS] ADDR ...");
fail:
- if (add) {
- a_addfree(add);
- xfree(add);
- }
+ xfree(add->peer.name);
+ xfree(add);
return;
}
}
if (!av[i]) goto bad_syntax;
- if ((p = p_find(av[i])) == 0) {
- a_fail(a, "unknown-peer %s", av[i]);
+ if ((p = a_findpeer(a, av[i])) == 0)
return;
- }
pg = xmalloc(sizeof(*pg));
gettimeofday(&pg->pingtime, 0);
a_bgadd(a, &pg->bg, tag, a_pingcancel);
{
peer *p;
- if ((p = p_find(av[0])) == 0)
- a_fail(a, "unknown-peer %s", av[0]);
- else {
+ if ((p = a_findpeer(a, av[0])) != 0) {
a_info(a, "%s", p_ifname(p));
a_ok(a);
}
}
+static void acmd_getchal(admin *a, unsigned ac, char *av[])
+{
+ buf b;
+
+ buf_init(&b, buf_i, PKBUFSZ);
+ c_new(&b);
+ a_info(a, "%s", b64_encode(BBASE(&b), BLEN(&b)));
+ a_ok(a);
+}
+
+static void acmd_checkchal(admin *a, unsigned ac, char *av[])
+{
+ base64_ctx b64;
+ buf b;
+ dstr d = DSTR_INIT;
+
+ base64_init(&b64);
+ base64_decode(&b64, av[0], strlen(av[0]), &d);
+ base64_decode(&b64, 0, 0, &d);
+ buf_init(&b, d.buf, d.len);
+ if (c_check(&b) || BBAD(&b) || BLEFT(&b))
+ a_fail(a, "invalid-challenge");
+ else
+ a_ok(a);
+ dstr_destroy(&d);
+}
+
+static void acmd_greet(admin *a, unsigned ac, char *av[])
+{
+ peer *p;
+ base64_ctx b64;
+ dstr d = DSTR_INIT;
+
+ if ((p = a_findpeer(a, av[0])) != 0) {
+ base64_init(&b64);
+ base64_decode(&b64, av[1], strlen(av[1]), &d);
+ base64_decode(&b64, 0, 0, &d);
+ p_greet(p, d.buf, d.len);
+ dstr_destroy(&d);
+ a_ok(a);
+ }
+}
+
static void acmd_addr(admin *a, unsigned ac, char *av[])
{
peer *p;
const addr *ad;
- if ((p = p_find(av[0])) == 0)
- a_fail(a, "unknown-peer %s", av[0]);
- else {
+ if ((p = a_findpeer(a, av[0])) != 0) {
ad = p_addr(p);
assert(ad->sa.sa_family == AF_INET);
a_info(a, "INET %s %u",
peer *p;
const peerspec *ps;
- if ((p = p_find(av[0])) == 0) {
- a_fail(a, "unknown-peer %s", av[0]);
- return;
+ if ((p = a_findpeer(a, av[0])) != 0) {
+ ps = p_spec(p);
+ a_info(a, "tunnel=%s", ps->tops->name);
+ a_info(a, "keepalive=%lu", ps->t_ka);
+ a_ok(a);
}
-
- ps = p_spec(p);
- a_info(a, "tunnel=%s", ps->tops->name);
- a_info(a, "keepalive=%lu", ps->t_ka);
- a_ok(a);
}
static void acmd_servinfo(admin *a, unsigned ac, char *av[])
peer *p;
stats *st;
- if ((p = p_find(av[0])) == 0) {
- a_fail(a, "unknown-peer %s", av[0]);
+ if ((p = a_findpeer(a, av[0])) == 0)
return;
- }
st = p_stats(p);
a_info(a, "start-time=%s", timestr(st->t_start));
static void acmd_kill(admin *a, unsigned ac, char *av[])
{
peer *p;
- if ((p = p_find(av[0])) == 0)
- a_fail(a, "unknown-peer %s", av[0]);
- else {
+ if ((p = a_findpeer(a, av[0])) != 0) {
p_destroy(p);
a_ok(a);
}
static void acmd_forcekx(admin *a, unsigned ac, char *av[])
{
peer *p;
- if ((p = p_find(av[0])) == 0)
- a_fail(a, "unknown-peer %s", av[0]);
- else {
+ if ((p = a_findpeer(a, av[0])) != 0) {
kx_start(&p->kx, 1);
a_ok(a);
}
{ "add", "add PEER [OPTIONS] ADDR ...",
2, 0xffff, acmd_add },
{ "addr", "addr PEER", 1, 1, acmd_addr },
+ { "checkchal", "checkchal CHAL", 1, 1, acmd_checkchal },
{ "daemon", "daemon", 0, 0, acmd_daemon },
{ "eping", "eping [OPTIONS] PEER", 1, 0xffff, acmd_eping },
{ "forcekx", "forcekx PEER", 1, 1, acmd_forcekx },
+ { "getchal", "getchal", 0, 0, acmd_getchal },
+ { "greet", "greet PEER CHAL", 2, 2, acmd_greet },
{ "help", "help", 0, 0, acmd_help },
{ "ifname", "ifname PEER", 1, 1, acmd_ifname },
{ "kill", "kill PEER", 1, 1, acmd_kill },