From ff72e68fcde755cddd425599c83dc052aeff6efb Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 13 Oct 2015 14:14:08 +0200 Subject: [PATCH] Determine the local node's address(es) and add them to its host config file. Use the "UDP connect() to an external IP address" trick to determine the local node's addresses in a platform independent way, without sending any actual packets. Do this at meshlink_open() time, so the application has immediate access to them when calling meshlink_export(). --- src/meshlink.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/meshlink.c b/src/meshlink.c index addb4900..cbbb64d3 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -712,6 +712,65 @@ static struct timeval idle(event_loop_t *loop, void *data) { return tmin; } +// Find out what local address a socket would use if we connect to the given address. +// We do this using connect() on a UDP socket, so the kernel has to resolve the address +// of both endpoints, but this will actually not send any UDP packet. +static bool getlocaladdrname(char *destaddr, char *host, socklen_t hostlen) { + struct addrinfo *rai = NULL; + const struct addrinfo hint = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, + }; + + if(getaddrinfo(destaddr, "80", &hint, &rai) || !rai) + return false; + + int sock = socket(rai->ai_family, rai->ai_socktype, rai->ai_protocol); + if(sock == -1) { + freeaddrinfo(rai); + return false; + } + + if(connect(sock, rai->ai_addr, rai->ai_addrlen) && !sockwouldblock(errno)) { + freeaddrinfo(rai); + return false; + } + + freeaddrinfo(rai); + + struct sockaddr_storage sn; + socklen_t sl = sizeof sn; + + if(getsockname(sock, (struct sockaddr *)&sn, &sl)) + return false; + + if(getnameinfo((struct sockaddr *)&sn, sl, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) + return false; + + return true; +} + +// Get our local address(es) by simulating connecting to an Internet host. +static void add_local_addresses(meshlink_handle_t *mesh) { + char host[NI_MAXHOST]; + char entry[MAX_STRING_SIZE]; + + // IPv4 example.org + + if(getlocaladdrname("93.184.216.34", host, sizeof host)) { + snprintf(entry, sizeof entry, "%s %s", host, mesh->myport); + append_config_file(mesh, mesh->name, "Address", entry); + } + + // IPv6 example.org + + if(getlocaladdrname("2606:2800:220:1:248:1893:25c8:1946", host, sizeof host)) { + snprintf(entry, sizeof entry, "%s %s", host, mesh->myport); + append_config_file(mesh, mesh->name, "Address", entry); + } +} + static bool meshlink_setup(meshlink_handle_t *mesh) { if(mkdir(mesh->confbase, 0777) && errno != EEXIST) { logger(mesh, MESHLINK_DEBUG, "Could not create directory %s: %s\n", mesh->confbase, strerror(errno)); @@ -853,6 +912,8 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c return NULL; } + add_local_addresses(mesh); + idle_set(&mesh->loop, idle, mesh); logger(NULL, MESHLINK_DEBUG, "meshlink_open returning\n"); -- 2.39.5