#define F_INIT 2u
#define T_RESOLVE SEC(30)
+#define T_PING SEC(5)
static void a_destroy(admin */*a*/);
static void a_lock(admin */*a*/);
/*----- Output functions --------------------------------------------------*/
-/* --- @mystrieq@ --- *
- *
- * Arguments: @const char *x, *y@ = two strings
- *
- * Returns: True if @x@ and @y are equal, up to case.
- */
-
-static int mystrieq(const char *x, const char *y)
-{
- for (;;) {
- if (!*x && !*y) return (1);
- if (tolower((unsigned char)*x) != tolower((unsigned char)*y))
- return (0);
- x++; y++;
- }
-}
-
/* --- @trywrite@ --- *
*
* Arguments: @admin *a@ = pointer to an admin block
void a_quit(void)
{
+ peer *p;
+
+ while ((p = p_first()) != 0)
+ p_destroy(p);
close(sock.fd);
unlink(sockname);
exit(0);
a_warn("SERVER ignore signal SIGHUP");
}
+/* --- @a_parsetime@ --- *
+ *
+ * Arguments; @const char *p@ = time string to parse
+ *
+ * Returns: Time in seconds, or @< 0@ on error.
+ */
+
+static long a_parsetime(const char *p)
+{
+ char *q;
+ long t = strtol(p, &q, 0);
+
+ switch (*q) {
+ case 'd': t *= 24;
+ case 'h': t *= 60;
+ case 'm': t *= 60;
+ case 's': if (q[1] != 0)
+ default: t = -1;
+ case 0: break;
+ }
+ return (t);
+}
+
/*----- Adding peers ------------------------------------------------------*/
/* --- @a_resolve@ --- *
sel_rmtimer(&a->t);
if (!h)
a_fail(a, "resolve-error %s", a->paddr);
- else if (p_find(a->pname))
- a_fail(a, "peer-exists %s", a->pname);
+ else if (p_find(a->peer.name))
+ a_fail(a, "peer-exists %s", a->peer.name);
else {
- memcpy(&a->peer.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
- if (!p_create(a->pname, &a->peer.sa, a->sasz))
- a_fail(a, "peer-create-fail %s", a->pname);
+ memcpy(&a->peer.sa.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
+ if (!p_create(&a->peer))
+ a_fail(a, "peer-create-fail %s", a->peer.name);
else
a_ok(a);
}
- xfree(a->pname);
+ xfree(a->peer.name);
xfree(a->paddr);
- a->pname = 0;
+ a->peer.name = 0;
selbuf_enable(&a->b);
a_unlock(a);
}
T( trace(T_ADMIN, "admin: %u resolver timeout", a->seq); )
bres_abort(&a->r);
a_fail(a, "resolver-timeout %s\n", a->paddr);
- xfree(a->pname);
+ xfree(a->peer.name);
xfree(a->paddr);
- a->pname = 0;
+ a->peer.name = 0;
selbuf_enable(&a->b);
a_unlock(a);
}
{
unsigned long pt;
struct timeval tv;
- unsigned i;
+ unsigned i, j;
char *p;
/* --- Make sure someone's not got there already --- */
return;
}
- /* --- Fill in the easy bits of address --- */
+ /* --- Set stuff up --- */
+
+ a->peer.name = av[0];
+ a->peer.t_ka = 0;
+ a->peer.tops = tun_default;
+
+ /* --- Parse options --- */
- BURN(a->peer);
i = 1;
+ for (;;) {
+ if (!av[i])
+ goto bad_syntax;
+ if (mystrieq(av[i], "-tunnel")) {
+ if (!av[++i]) goto bad_syntax;
+ for (j = 0;; j++) {
+ if (!tunnels[j]) {
+ a_fail(a, "unknown-tunnel %s", av[i]);
+ return;
+ }
+ if (mystrieq(av[i], tunnels[j]->name)) {
+ a->peer.tops = tunnels[j];
+ break;
+ }
+ }
+ } else if (mystrieq(av[i], "-keepalive")) {
+ long t;
+ if (!av[++i]) goto bad_syntax;
+ if ((t = a_parsetime(av[i])) < 0) {
+ a_fail(a, "bad-time-spec %s", av[i]);
+ return;
+ }
+ a->peer.t_ka = t;
+ } else if (mystrieq(av[i], "--")) {
+ i++;
+ break;
+ } else
+ break;
+ 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 [inet] ADDRESS PORT");
+ a_fail(a, "bad-syntax -- add PEER [OPTIONS] [inet] ADDRESS PORT");
return;
}
- a->peer.sin.sin_family = AF_INET;
- a->sasz = sizeof(a->peer.sin);
+ a->peer.sa.sin.sin_family = AF_INET;
+ a->peer.sasz = sizeof(a->peer.sa.sin);
pt = strtoul(av[i + 1], &p, 0);
if (*p) {
struct servent *s = getservbyname(av[i + 1], "udp");
a_fail(a, "invalid-port %lu", pt);
return;
}
- a->peer.sin.sin_port = htons(pt);
+ a->peer.sa.sin.sin_port = htons(pt);
/* --- If the name is numeric, do it the easy way --- */
- if (inet_aton(av[i], &a->peer.sin.sin_addr)) {
- if (!p_create(av[0], &a->peer.sa, a->sasz))
- a_fail(a, "peer-create-fail %s", a->pname);
+ if (inet_aton(av[i], &a->peer.sa.sin.sin_addr)) {
+ if (!p_create(&a->peer))
+ a_fail(a, "peer-create-fail %s", av[0]);
else
a_ok(a);
+ a->peer.name = 0;
return;
}
* the system continues regardless), but makes life simpler for the client.
*/
- a->pname = xstrdup(av[0]);
+ a->peer.name = xstrdup(av[0]);
a->paddr = xstrdup(av[i]);
selbuf_disable(&a->b);
gettimeofday(&tv, 0);
bres_byname(&a->r, a->paddr, a_resolve, a);
T( trace(T_ADMIN, "admin: %u resolving hostname `%s'",
a->seq, a->paddr); )
+ return;
+
+bad_syntax:
+ a_fail(a, "bad-syntax -- add PEER [OPTIONS] ADDR ...");
+ return;
}
+/*----- Ping --------------------------------------------------------------*/
+
+/* --- @a_pong@ --- *
+ *
+ * Arguments: @int rc@ = return code
+ * @void *av@ = admin connection which requested the ping
+ *
+ * Returns: ---
+ *
+ * Use: Collects what happened to a ping message.
+ */
+
+static void a_pong(int rc, void *av)
+{
+ admin *a = av;
+ struct timeval tv;
+ double millis;
+
+ a_lock(a);
+ switch (rc) {
+ case PING_OK:
+ gettimeofday(&tv, 0);
+ tv_sub(&tv, &tv, &a->pingtime);
+ millis = (double)tv.tv_sec * 1000 + (double)tv.tv_usec/1000;
+ a_info(a, "ping-ok %.1f", millis);
+ a_ok(a);
+ break;
+ case PING_TIMEOUT:
+ a_info(a, "ping-timeout");
+ a_ok(a);
+ break;
+ case PING_PEERDIED:
+ a_info(a, "ping-peer-died");
+ a_ok(a);
+ break;
+ default:
+ abort();
+ }
+ a_unlock(a);
+}
+
+/* --- @acmd_ping@, @acmd_eping@ --- *
+ *
+ * Arguments: @admin *a@ = connection which requested the ping
+ * @unsigned ac@ = argument count
+ * @char *av[]@ = pointer to the argument list
+ *
+ * Returns: ---
+ *
+ * Use: Pings a peer.
+ */
+
+static void a_ping(admin *a, unsigned ac, char *av[],
+ const char *cmd, unsigned msg)
+{
+ long t = T_PING;
+ int i;
+ peer *p;
+
+ i = 0;
+ for (;;) {
+ if (!av[i])
+ goto bad_syntax;
+ if (mystrieq(av[i], "-timeout")) {
+ if (!av[++i]) goto bad_syntax;
+ if ((t = a_parsetime(av[i])) < 0) {
+ a_fail(a, "bad-time-spec %s", av[i]);
+ return;
+ }
+ } else if (mystrieq(av[i], "--")) {
+ i++;
+ break;
+ } else
+ break;
+ i++;
+ }
+
+ if (!av[i]) goto bad_syntax;
+ if ((p = p_find(av[i])) == 0) {
+ a_fail(a, "unknown-peer %s", av[i]);
+ return;
+ }
+ gettimeofday(&a->pingtime, 0);
+ if (p_pingsend(p, &a->ping, msg, t, a_pong, a))
+ a_fail(a, "ping-send-failed");
+ return;
+
+bad_syntax:
+ a_fail(a, "bad-syntax -- %s [OPTIONS] PEER", cmd);
+ return;
+}
+
+static void acmd_ping(admin *a, unsigned ac, char *av[])
+ { a_ping(a, ac, av, "ping", MISC_PING); }
+static void acmd_eping(admin *a, unsigned ac, char *av[])
+ { a_ping(a, ac, av, "eping", MISC_EPING); }
+
+
/*----- Administration commands -------------------------------------------*/
/* --- Miscellaneous commands --- */
}
}
+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 {
+ kx_start(&p->kx);
+ a_ok(a);
+ }
+}
+
static void acmd_quit(admin *a, unsigned ac, char *av[])
{
a_warn("SERVER quit admin-request");
a_ok(a);
}
+static void acmd_tunnels(admin *a, unsigned ac, char *av[])
+{
+ int i;
+ for (i = 0; tunnels[i]; i++)
+ a_info(a, "%s", tunnels[i]->name);
+ a_ok(a);
+}
+
/* --- The command table and help --- */
typedef struct acmd {
{ "ifname", "ifname PEER", 1, 1, acmd_ifname },
{ "addr", "addr PEER", 1, 1, acmd_addr },
{ "stats", "stats PEER", 1, 1, acmd_stats },
+ { "ping", "ping [OPTIONS] PEER", 1, 0xffff, acmd_ping },
+ { "eping", "eping [OPTIONS] PEER", 1, 0xffff, acmd_eping },
{ "kill", "kill PEER", 1, 1, acmd_kill },
- { "add", "add PEER ADDR ...", 2, 0xffff, acmd_add },
+ { "forcekx", "forcekx PEER", 1, 1, acmd_forcekx },
+ { "add", "add PEER [OPTIONS] ADDR ...",
+ 2, 0xffff, acmd_add },
+ { "tunnels", "tunnels", 0, 0, acmd_tunnels },
{ "quit", "quit", 0, 0, acmd_quit },
{ 0, 0, 0, 0, 0 }
};
a->seq); )
selbuf_destroy(&a->b);
- if (a->pname) {
- xfree(a->pname);
+ if (a->peer.name) {
+ xfree(a->peer.name);
xfree(a->paddr);
bres_abort(&a->r);
sel_rmtimer(&a->t);
}
+ if (a->ping.p)
+ p_pingdone(&a->ping, PING_NONOTIFY);
if (a->b.reader.fd != a->w.fd)
close(a->b.reader.fd);
close(a->w.fd);
T( static unsigned seq = 0;
a->seq = seq++; )
T( trace(T_ADMIN, "admin: accepted connection %u", a->seq); )
- a->pname = 0;
+ a->peer.name = 0;
+ a->ping.p = 0;
a->f = f;
if (fd_in == STDIN_FILENO)
a_stdin = a;