about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--enroll.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/enroll.c b/enroll.c
index 7ef8e36..4ea8289 100644
--- a/enroll.c
+++ b/enroll.c
@@ -29,8 +29,11 @@
 #include <errno.h>
 #include <limits.h>
 #include <netdb.h>
+#include <netinet/in.h>
+#include <resolv.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -177,8 +180,44 @@ static int getConfig(const char *configHome) {
 }
 
 static int srvLookup(char **host, char **port, const char *name) {
-	// TODO
-	return -1;
+	char dname[256];
+	snprintf(dname, sizeof(dname), "_ircs._tcp.%s", name);
+	log("Looking up SRV record for %s", dname);
+
+	uint8_t msg[512];
+	int len = res_query(dname, 1 /* IN */, 33 /* SRV */, msg, sizeof(msg));
+	if (len < 12) return -1;
+
+	uint8_t *ptr = &msg[12];
+#define NAME_SKIP \
+	for (uint8_t n; ptr < &msg[len] && (n = *ptr++); ptr += n) { \
+		if (n & 0xC0) { ptr++; break; } \
+	}
+
+	uint16_t qdcount = msg[4] << 8 | msg[5];
+	for (uint16_t q = 0; ptr < &msg[len] && q < qdcount; ++q) {
+		NAME_SKIP; // QNAME
+		ptr += 4; // QTYPE, QCLASS
+	}
+
+	NAME_SKIP; // NAME
+	ptr += 14; // TYPE, CLASS, TTL, RDLENGTH, Priority, Weight
+	if (&msg[len] < ptr + 3) return -1;
+#undef NAME_SKIP
+
+	int n = asprintf(port, "%d", ptr[0] << 8 | ptr[1]);
+	if (n < 0) err(EX_OSERR, "asprintf");
+	ptr += 2;
+
+	// Name compression is not used for Target.
+	if (!ptr[0]) return -1;
+	char *host0 = (char *)&ptr[1];
+	for (uint8_t n; ptr < &msg[len] && (n = *ptr); ptr += n) {
+		*ptr++ = '.';
+	}
+	*host = strdup(host0);
+	if (!*host) err(EX_OSERR, "strdup");
+	return 0;
 }
 
 static int getHostPort(void) {