+static bool fcopy(FILE *out, const char *filename) {
+ FILE *in = fopen(filename, "r");
+ if(!in) {
+ fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
+ return false;
+ }
+
+ char buf[1024];
+ size_t len;
+ while((len = fread(buf, 1, sizeof buf, in)))
+ fwrite(buf, len, 1, out);
+ fclose(in);
+ return true;
+}
+
+static int rstrip(char *value) {
+ int len = strlen(value);
+ while(len && strchr("\t\r\n ", value[len - 1]))
+ value[--len] = 0;
+ return len;
+}
+
+static void scan_for_hostname(const char *filename, char **hostname, char **port) {
+ char line[4096];
+ if(!filename || (*hostname && *port))
+ return;
+
+ FILE *f = fopen(filename, "r");
+ if(!f)
+ return;
+
+ while(fgets(line, sizeof line, f)) {
+ if(!rstrip(line))
+ continue;
+ char *p = line, *q;
+ p += strcspn(p, "\t =");
+ if(!*p)
+ continue;
+ q = p + strspn(p, "\t ");
+ if(*q == '=')
+ q += 1 + strspn(q + 1, "\t ");
+ *p = 0;
+ p = q + strcspn(q, "\t ");
+ if(*p)
+ *p++ = 0;
+ p += strspn(p, "\t ");
+ p[strcspn(p, "\t ")] = 0;
+
+ if(!*port && !strcasecmp(line, "Port")) {
+ *port = xstrdup(q);
+ } else if(!*hostname && !strcasecmp(line, "Address")) {
+ *hostname = xstrdup(q);
+ if(*p) {
+ free(*port);
+ *port = xstrdup(p);
+ }
+ }
+
+ if(*hostname && *port)
+ break;
+ }
+
+ fclose(f);
+}
+static char *get_my_hostname(meshlink_handle_t* mesh) {
+ char *hostname = NULL;
+ char *port = NULL;
+ char *hostport = NULL;
+ char *name = mesh->self->name;
+ char filename[PATH_MAX] = "";
+ char line[4096];
+ FILE *f;
+
+ // Use first Address statement in own host config file
+ snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
+ scan_for_hostname(filename, &hostname, &port);
+
+ if(hostname)
+ goto done;
+
+ // If that doesn't work, guess externally visible hostname
+ fprintf(stderr, "Trying to discover externally visible hostname...\n");
+ struct addrinfo *ai = str2addrinfo("tinc-vpn.org", "80", SOCK_STREAM);
+ struct addrinfo *aip = ai;
+ static const char request[] = "GET http://tinc-vpn.org/host.cgi HTTP/1.0\r\n\r\n";
+
+ while(aip) {
+ int s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
+ if(s >= 0) {
+ if(connect(s, aip->ai_addr, aip->ai_addrlen)) {
+ closesocket(s);
+ s = -1;
+ }
+ }
+ if(s >= 0) {
+ send(s, request, sizeof request - 1, 0);
+ int len = recv(s, line, sizeof line - 1, MSG_WAITALL);
+ if(len > 0) {
+ line[len] = 0;
+ if(line[len - 1] == '\n')
+ line[--len] = 0;
+ char *p = strrchr(line, '\n');
+ if(p && p[1])
+ hostname = xstrdup(p + 1);
+ }
+ closesocket(s);
+ if(hostname)
+ break;
+ }
+ aip = aip->ai_next;
+ continue;
+ }
+
+ if(ai)
+ freeaddrinfo(ai);
+
+ // Check that the hostname is reasonable
+ if(hostname) {
+ for(char *p = hostname; *p; p++) {
+ if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')
+ continue;
+ // If not, forget it.
+ free(hostname);
+ hostname = NULL;
+ break;
+ }
+ }
+
+ //if(!tty) {
+ // if(!hostname) {
+ // fprintf(stderr, "Could not determine the external address or hostname. Please set Address manually.\n");
+ // return NULL;
+ // }
+ // goto save;
+ //}
+
+again:
+ fprintf(stderr, "Please enter your host's external address or hostname");
+ if(hostname)
+ fprintf(stderr, " [%s]", hostname);
+ fprintf(stderr, ": ");
+
+ if(!fgets(line, sizeof line, stdin)) {
+ fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
+ free(hostname);
+ return NULL;
+ }
+
+ if(!rstrip(line)) {
+ if(hostname)
+ goto save;
+ else
+ goto again;
+ }
+
+ for(char *p = line; *p; p++) {
+ if(isalnum(*p) || *p == '-' || *p == '.')
+ continue;
+ fprintf(stderr, "Invalid address or hostname.\n");
+ goto again;
+ }
+
+ free(hostname);
+ hostname = xstrdup(line);
+
+save:
+ f = fopen(filename, "a");
+ if(f) {
+ fprintf(f, "\nAddress = %s\n", hostname);
+ fclose(f);
+ } else {
+ fprintf(stderr, "Could not append Address to %s: %s\n", filename, strerror(errno));
+ }
+
+done:
+ if(port) {
+ if(strchr(hostname, ':'))
+ xasprintf(&hostport, "[%s]:%s", hostname, port);
+ else
+ xasprintf(&hostport, "%s:%s", hostname, port);
+ } else {
+ if(strchr(hostname, ':'))
+ xasprintf(&hostport, "[%s]", hostname);
+ else
+ hostport = xstrdup(hostname);
+ }
+
+ free(hostname);
+ free(port);
+ return hostport;
+}
+