+ if(!(flags & (MESHLINK_INVITE_IPV4 | MESHLINK_INVITE_IPV6))) {
+ flags |= MESHLINK_INVITE_IPV4 | MESHLINK_INVITE_IPV6;
+ }
+
+ // Add local addresses if requested
+ if(flags & MESHLINK_INVITE_LOCAL) {
+ if(flags & MESHLINK_INVITE_IPV4) {
+ hostname[0] = meshlink_get_local_address_for_family(mesh, AF_INET);
+ }
+
+ if(flags & MESHLINK_INVITE_IPV6) {
+ hostname[1] = meshlink_get_local_address_for_family(mesh, AF_INET6);
+ }
+ }
+
+ // Add public/canonical addresses if requested
+ if(flags & MESHLINK_INVITE_PUBLIC) {
+ // Try the CanonicalAddress first
+ char filename[PATH_MAX] = "";
+ snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->self->name);
+ scan_for_canonical_address(filename, &hostname[2], &port[2]);
+
+ if(!hostname[2]) {
+ if(flags & MESHLINK_INVITE_IPV4) {
+ hostname[2] = meshlink_get_external_address_for_family(mesh, AF_INET);
+ }
+
+ if(flags & MESHLINK_INVITE_IPV6) {
+ hostname[3] = meshlink_get_external_address_for_family(mesh, AF_INET6);
+ }
+ }
+ }
+
+ for(int i = 0; i < 4; i++) {
+ // Ensure we always have a port number
+ if(hostname[i] && !port[i]) {
+ port[i] = xstrdup(mesh->myport);
+ }
+ }
+
+ remove_duplicate_hostnames(hostname, port, 4);
+
+ if(!(flags & MESHLINK_INVITE_NUMERIC)) {
+ for(int i = 0; i < 4; i++) {
+ if(!hostname[i]) {
+ continue;
+ }
+
+ // Convert what we have to a sockaddr
+ struct addrinfo *ai_in, *ai_out;
+ struct addrinfo hint = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_NUMERICSERV,
+ .ai_socktype = SOCK_STREAM,
+ };
+ int err = getaddrinfo(hostname[i], port[i], &hint, &ai_in);
+
+ if(err || !ai_in) {
+ continue;
+ }
+
+ // Convert it to a hostname
+ char resolved_host[NI_MAXHOST];
+ char resolved_port[NI_MAXSERV];
+ err = getnameinfo(ai_in->ai_addr, ai_in->ai_addrlen, resolved_host, sizeof resolved_host, resolved_port, sizeof resolved_port, NI_NUMERICSERV);
+
+ if(err) {
+ freeaddrinfo(ai_in);
+ continue;
+ }
+
+ // Convert the hostname back to a sockaddr
+ hint.ai_family = ai_in->ai_family;
+ err = getaddrinfo(resolved_host, resolved_port, &hint, &ai_out);
+
+ if(err || !ai_out) {
+ freeaddrinfo(ai_in);
+ continue;
+ }
+
+ // Check if it's still the same sockaddr
+ if(ai_in->ai_addrlen != ai_out->ai_addrlen || memcmp(ai_in->ai_addr, ai_out->ai_addr, ai_in->ai_addrlen)) {
+ freeaddrinfo(ai_in);
+ freeaddrinfo(ai_out);
+ continue;
+ }
+
+ // Yes: replace the hostname with the resolved one
+ free(hostname[i]);
+ hostname[i] = xstrdup(resolved_host);
+
+ freeaddrinfo(ai_in);
+ freeaddrinfo(ai_out);
+ }
+ }
+
+ // Remove duplicates again, since IPv4 and IPv6 addresses might map to the same hostname
+ remove_duplicate_hostnames(hostname, port, 4);
+
+ // Concatenate all unique address to the hostport string
+ for(int i = 0; i < 4; i++) {
+ if(!hostname[i]) {
+ continue;
+ }
+
+ // Ensure we have the same addresses in our own host config file.
+ char *tmphostport;
+ xasprintf(&tmphostport, "%s %s", hostname[i], port[i]);
+ append_config_file(mesh, mesh->self->name, "Address", tmphostport);
+ free(tmphostport);
+
+ // Append the address to the hostport string
+ char *newhostport;
+ xasprintf(&newhostport, (strchr(hostname[i], ':') ? "%s%s[%s]:%s" : "%s%s%s:%s"), hostport ? hostport : "", hostport ? "," : "", hostname[i], port[i]);
+ free(hostport);
+ hostport = newhostport;
+
+ free(hostname[i]);
+ free(port[i]);