From 5d06f63eaa34a4bf0e116f3e2a1e4ef4e6434224 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sat, 16 Sep 2017 15:30:42 +0100 Subject: [PATCH] server/: Institute `address family table'; contemplate multiple sockets. This is a slightly oddly-shaped change which lays important groundwork for the future. * Firstly, it creates a table of address families, currently not very interestingly since there's only one, but this will be an essential tool for adding IPv6 support later. * Secondly, it turns the peer module's `sock' into a global vector `udpsock' of UDP sockets, possibly one for each of the supported address families. There's no real change here, because there's only one address family known, but the `port' command has grown an address-family argument in case they have different ports. To make this work, each peer now keeps track of the index of the socket it should use for transmitting messages. --- py/tripe.py.in | 6 ++++-- server/admin.c | 21 +++++++++++++++++++-- server/peer.c | 21 ++++++++++++++------- server/servutil.c | 24 ++++++++++++++++++++++++ server/tripe-admin.5.in | 17 +++++++++++++++-- server/tripe.h | 32 ++++++++++++++++++++++++++++++-- 6 files changed, 106 insertions(+), 15 deletions(-) diff --git a/py/tripe.py.in b/py/tripe.py.in index 5562d7b3..29911b0e 100644 --- a/py/tripe.py.in +++ b/py/tripe.py.in @@ -878,8 +878,10 @@ class TripeCommandDispatcher (TripeConnection): *['PING'] + _kwopts(kw, ['timeout']) + [peer])) - def port(me): - return _oneline(me.command('PORT', filter = _tokenjoin)) + def port(me, af = None): + return _oneline(me.command('PORT', + *((af is not None) and [af] or []), + filter = _tokenjoin)) def quit(me): return _simple(me.command('QUIT')) def reload(me): diff --git a/server/admin.c b/server/admin.c index 46a7348a..3b99848c 100644 --- a/server/admin.c +++ b/server/admin.c @@ -1666,7 +1666,24 @@ static void acmd_warn(admin *a, unsigned ac, char *av[]) { alertcmd(a, AF_WARN, AF_WARN, "WARN", av); } static void acmd_port(admin *a, unsigned ac, char *av[]) - { a_info(a, "%u", p_port(), A_END); a_ok(a); } +{ + int i; + + if (ac) { + for (i = 0; i < NADDRFAM; i++) + if (mystrieq(av[0], aftab[i].name)) goto found; + a_fail(a, "unknown-address-family", "%s", av[0], A_END); + return; + found: + assert(udpsock[i].fd >= 0); + } else { + for (i = 0; i < NADDRFAM; i++) + if (udpsock[i].fd >= 0) goto found; + abort(); + } + a_info(a, "%u", p_port(i), A_END); + a_ok(a); +} static void acmd_daemon(admin *a, unsigned ac, char *av[]) { @@ -1977,7 +1994,7 @@ static const acmd acmdtab[] = { { "notify", "MESSAGE ...", 1, 0xffff, acmd_notify }, { "peerinfo", "PEER", 1, 1, acmd_peerinfo }, { "ping", "[OPTIONS] PEER", 1, 0xffff, acmd_ping }, - { "port", 0, 0, 0, acmd_port }, + { "port", "[FAMILY]", 0, 1, acmd_port }, { "quit", 0, 0, 0, acmd_quit }, { "reload", 0, 0, 0, acmd_reload }, { "servinfo", 0, 0, 0, acmd_servinfo }, diff --git a/server/peer.c b/server/peer.c index 03ed2ae3..ba8d7baf 100644 --- a/server/peer.c +++ b/server/peer.c @@ -27,11 +27,14 @@ #include "tripe.h" +/*----- Global state ------------------------------------------------------*/ + +sel_file udpsock[NADDRFAM]; + /*----- Static variables --------------------------------------------------*/ static sym_table byname; static addrmap byaddr; -static sel_file sock; static unsigned nmobile; /*----- Tunnel table ------------------------------------------------------*/ @@ -181,6 +184,7 @@ int p_updateaddr(peer *p, const addr *a) { peer *q; peer_byaddr *pa, *qa; + int ix; unsigned f; /* --- Figure out how to proceed --- * @@ -197,6 +201,7 @@ int p_updateaddr(peer *p, const addr *a) T( trace(T_PEER, "peer: updating address for `%s'", p_name(p)); ) am_remove(&byaddr, p->byaddr); p->byaddr = pa; p->spec.sa = *a; pa->p = p; + p->afix = afix(p->spec.sa.sa.sa_family); assert(p->afix >= 0); a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); return (0); } else { @@ -205,6 +210,7 @@ int p_updateaddr(peer *p, const addr *a) p_name(p), p_name(q)); ) q->byaddr = qa; qa->p = q; q->spec.sa = p->spec.sa; p->byaddr = pa; pa->p = p; p->spec.sa = *a; + ix = p->afix; p->afix = q->afix; q->afix = ix; a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END); a_notify("NEWADDR", "?PEER", q, "?ADDR", &q->spec.sa, A_END); return (0); @@ -510,7 +516,7 @@ static int p_dotxend(peer *p) } IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", BBASE(&p->b), BLEN(&p->b)); ) - if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b), + if (sendto(udpsock[p->afix].fd, BBASE(&p->b), BLEN(&p->b), 0, &p->spec.sa.sa, sasz) < 0) { a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END); return (0); @@ -802,8 +808,8 @@ void p_init(struct in_addr addr, unsigned port) strerror(errno)); } fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); - sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0); - sel_addfile(&sock); + sel_initfile(&sel, &udpsock[AFIX_INET], fd, SEL_READ, p_read, 0); + sel_addfile(&udpsock[AFIX_INET]); T( trace(T_PEER, "peer: created socket"); ) sym_create(&byname); @@ -812,17 +818,17 @@ void p_init(struct in_addr addr, unsigned port) /* --- @p_port@ --- * * - * Arguments: --- + * Arguments: @int i@ = address family index to retrieve * * Returns: Port number used for socket. */ -unsigned p_port(void) +unsigned p_port(int i) { addr a; socklen_t sz = sizeof(addr); - if (getsockname(sock.fd, &a.sa, &sz)) + if (getsockname(udpsock[i].fd, &a.sa, &sz)) die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno)); assert(a.sa.sa_family == AF_INET); return (ntohs(a.sin.sin_port)); @@ -898,6 +904,7 @@ peer *p_create(peerspec *spec) p->ks = 0; p->pings = 0; p->ifname = 0; + p->afix = afix(p->spec.sa.sa.sa_family); assert(p->afix >= 0); memset(&p->st, 0, sizeof(stats)); p->st.t_start = time(0); if (!(tops->flags & TUNF_PRIVOPEN)) diff --git a/server/servutil.c b/server/servutil.c index 70721396..70776dda 100644 --- a/server/servutil.c +++ b/server/servutil.c @@ -121,6 +121,30 @@ int mystrieq(const char *x, const char *y) } } +/*----- Address handling --------------------------------------------------*/ + +const struct addrfam aftab[] = { +#define DEF(af) { AF_##af, #af }, + ADDRFAM(DEF) +#undef DEF +}; + +/* --- @afix@ --- * + * + * Arguments: @int af@ = an address family code + * + * Returns: The index of the address family's record in @aftab@, or @-1@. + */ + +int afix(int af) +{ + int i; + + for (i = 0; i < NADDRFAM; i++) + if (af == aftab[i].af) return (i); + return (-1); +} + /* --- @addrsz@ --- * * * Arguments: @const addr *a@ = a network address diff --git a/server/tripe-admin.5.in b/server/tripe-admin.5.in index 5836eeae..43f77254 100644 --- a/server/tripe-admin.5.in +++ b/server/tripe-admin.5.in @@ -663,12 +663,18 @@ given, seconds are assumed. .RE .SP .B "PORT" +.RI [ family ] Emits an .B INFO line containing just the number of the UDP port used by the .B tripe -server. If you've allowed your server to allocate a port dynamically, -this is how to find out which one it chose. +server, for the given address +.I family +(or one chosen arbitrarily if omitted -- though +.B tripe +tries to use the same port number consistently so this is not a likely +problem in practice). If you've allowed your server to allocate a port +dynamically, this is how to find out which one it chose. .SP .B "RELOAD" Instructs the server to recheck its keyring files. The server checks @@ -1079,6 +1085,13 @@ is available, which does not meet the stated requirements. .I tag is already the tag of an outstanding job. .SP +.BI "unknown-address-family " afam +(For +.BR PORT .) +The address family +.I afam +is unrecognized. +.SP .BI "unknown-command " token The command .I token diff --git a/server/tripe.h b/server/tripe.h index 4b6c7101..0eae8dc5 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -410,6 +410,23 @@ extern const bulkops bulktab[]; /*----- Data structures ---------------------------------------------------*/ +/* --- The address-family table --- */ + +#define ADDRFAM(_) \ + _(INET) + +enum { +#define ENUM(af) AFIX_##af, + ADDRFAM(ENUM) +#undef ENUM + NADDRFAM +}; + +extern const struct addrfam { + int af; + const char *name; +} aftab[NADDRFAM]; + /* --- Socket addresses --- * * * A magic union of supported socket addresses. @@ -615,6 +632,7 @@ typedef struct peer { peer_byaddr *byaddr; /* Lookup-by-address block */ struct ping *pings; /* Pings we're waiting for */ peerspec spec; /* Specifications for this peer */ + int afix; /* Index of address family */ tunnel *t; /* Tunnel for local packets */ char *ifname; /* Interface name for tunnel */ keyset *ks; /* List head for keysets */ @@ -757,6 +775,7 @@ extern sel_state sel; /* Global I/O event state */ extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ], buf_u[PKBUFSZ]; extern const tunnel_ops *tunnels[]; /* Table of tunnels (0-term) */ extern const tunnel_ops *tun_default; /* Default tunnel to use */ +extern sel_file udpsock[NADDRFAM]; /* The master UDP sockets */ extern kdata *master; /* Default private key */ extern const char *tag_priv; /* Default private key tag */ @@ -1577,12 +1596,12 @@ extern void p_init(struct in_addr /*addr*/, unsigned /*port*/); /* --- @p_port@ --- * * - * Arguments: --- + * Arguments: @int i@ = address family index to retrieve * * Returns: Port number used for socket. */ -unsigned p_port(void); +extern unsigned p_port(int /*i*/); /* --- @p_create@ --- * * @@ -1742,6 +1761,15 @@ extern const char *timestr(time_t /*t*/); extern int mystrieq(const char */*x*/, const char */*y*/); +/* --- @afix@ --- * + * + * Arguments: @int af@ = an address family code + * + * Returns: The index of the address family's record in @aftab@, or @-1@. + */ + +extern int afix(int af); + /* --- @addrsz@ --- * * * Arguments: @const addr *a@ = a network address -- 2.11.0