X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/blobdiff_plain/067aa5f013dd6108e81c1df0c2ed19491802bc69..4a3882945f605704ede113a9fe98cd19a92363a7:/server/peer.c diff --git a/server/peer.c b/server/peer.c index 606b2038..a8099e41 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); @@ -330,6 +336,10 @@ static void p_read(int fd, unsigned mode, void *v) ssize_t n; int ch; buf b, bb; +#ifndef NTRACE + int ix = -1; + char name[NI_MAXHOST], svc[NI_MAXSERV]; +#endif /* --- Read the data --- */ @@ -340,14 +350,18 @@ static void p_read(int fd, unsigned mode, void *v) a_warn("PEER", "-", "socket-read-error", "?ERRNO", A_END); return; } + IF_TRACING(T_PEER, { + ix = afix(a.sa.sa_family); + getnameinfo(&a.sa, sz, name, sizeof(name), svc, sizeof(svc), + NI_NUMERICHOST | NI_NUMERICSERV); + }) /* --- If the packet is a greeting, don't check peers --- */ if (n && buf_i[0] == (MSG_MISC | MISC_GREET)) { IF_TRACING(T_PEER, { - trace(T_PEER, "peer: greeting received from INET %s %u", - inet_ntoa(a.sin.sin_addr), - (unsigned)ntohs(a.sin.sin_port)); + trace(T_PEER, "peer: greeting received from %s %s %s", + aftab[ix].name, name, svc); trace_block(T_PACKET, "peer: greeting contents", buf_i, n); }) buf_init(&b, buf_i, n); @@ -373,11 +387,11 @@ static void p_read(int fd, unsigned mode, void *v) IF_TRACING(T_PEER, { if (p) { trace(T_PEER, - "peer: packet received from `%s' from address INET %s %d", - p_name(p), inet_ntoa(a.sin.sin_addr), ntohs(a.sin.sin_port)); + "peer: packet received from `%s' from address %s %s %s", + p_name(p), aftab[ix].name, name, svc); } else { - trace(T_PEER, "peer: packet received from unknown address INET %s %d", - inet_ntoa(a.sin.sin_addr), ntohs(a.sin.sin_port)); + trace(T_PEER, "peer: packet received from unknown address %s %s %s", + aftab[ix].name, name, svc); } trace_block(T_PACKET, "peer: packet contents", buf_i, n); }) @@ -543,7 +557,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); @@ -799,45 +813,68 @@ const addr *p_addr(peer *p) { return (&p->spec.sa); } /* --- @p_init@ --- * * - * Arguments: @struct in_addr addr@ = address to bind to - * @unsigned port@ = port number to listen to + * Arguments: @struct addrinfo *ailist@ = addresses to bind to * * Returns: --- * * Use: Initializes the peer system; creates the socket. */ -void p_init(struct in_addr addr, unsigned port) +void p_init(struct addrinfo *ailist) { int fd; - struct sockaddr_in sin; int len = PKBUFSZ; + int yes = 1; + int i; + struct addrinfo *ai; + unsigned port, lastport = 0; + addr a; + socklen_t sz; - /* --- Note on socket buffer sizes --- * - * - * For some bizarre reason, Linux 2.2 (at least) doubles the socket buffer - * sizes I pass to @setsockopt@. I'm not putting special-case code here - * for Linux: BSD (at least TCPv2) does what I tell it rather than second- - * guessing me. - */ - - if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); - BURN(sin); - sin.sin_family = AF_INET; - sin.sin_addr = addr; - sin.sin_port = htons(port); - if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) - die(EXIT_FAILURE, "bind failed: %s", strerror(errno)); - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || - setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { - die(EXIT_FAILURE, "failed to set socket buffer sizes: %s", - strerror(errno)); + for (i = 0; i < NADDRFAM; i++) udpsock[i].fd = -1; + + for (ai = ailist; ai; ai = ai->ai_next) { + if ((i = afix(ai->ai_family)) < 0) continue; + if (udpsock[i].fd != -1) continue; + + /* --- Note on socket buffer sizes --- * + * + * For some bizarre reason, Linux 2.2 (at least) doubles the socket + * buffer sizes I pass to @setsockopt@. I'm not putting special-case + * code here for Linux: BSD (at least TCPv2) does what I tell it rather + * than second-guessing me. + */ + + if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0) + die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); + if (i == AFIX_INET6 && + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) { + die(EXIT_FAILURE, "failed to set IPv6-only state: %s", + strerror(errno)); + } + assert(ai->ai_addrlen <= sizeof(a)); + memcpy(&a, ai->ai_addr, ai->ai_addrlen); + if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport); + if (bind(fd, &a.sa, addrsz(&a))) + die(EXIT_FAILURE, "bind failed: %s", strerror(errno)); + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { + die(EXIT_FAILURE, "failed to set socket buffer sizes: %s", + strerror(errno)); + } + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); + sel_initfile(&sel, &udpsock[i], fd, SEL_READ, p_read, 0); + sel_addfile(&udpsock[i]); + T( trace(T_PEER, "peer: created %s socket", aftab[i].name); ) + if (!port) { + sz = sizeof(a); + if (getsockname(fd, &a.sa, &sz)) { + die(EXIT_FAILURE, "failed to read local socket address: %s", + strerror(errno)); + } + lastport = getport(&a); + } } - fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); - sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0); - sel_addfile(&sock); - T( trace(T_PEER, "peer: created socket"); ) sym_create(&byname); am_create(&byaddr); @@ -845,20 +882,19 @@ 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)); + return (getport(&a)); } /* --- @p_keepalive@ --- * @@ -932,6 +968,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))