Browse Source

add the ability to announce additional hostnames

Signed-off-by: John Crispin <john@phrozen.org>
John Crispin 5 months ago
parent
commit
3b341f4183
6 changed files with 82 additions and 8 deletions
  1. 2 1
      announce.c
  2. 16 5
      dns.c
  3. 2 1
      dns.h
  4. 2 1
      interface.c
  5. 53 0
      service.c
  6. 7 0
      service.h

+ 2 - 1
announce.c

@@ -65,7 +65,8 @@ announce_timer(struct uloop_timeout *timeout)
 			/* Fall through */
 
 		case STATE_ANNOUNCE:
-			dns_reply_a(iface, NULL, announce_ttl);
+			dns_reply_a(iface, NULL, announce_ttl, NULL);
+			dns_reply_a_additional(iface, NULL, announce_ttl);
 			service_announce_services(iface, NULL, announce_ttl);
 			uloop_timeout_set(timeout, announce_ttl * 800);
 			break;

+ 16 - 5
dns.c

@@ -183,7 +183,7 @@ dns_send_answer(struct interface *iface, struct sockaddr *to, const char *answer
 }
 
 void
-dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl)
+dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname)
 {
 	struct ifaddrs *ifap, *ifa;
 	struct sockaddr_in *sa;
@@ -204,11 +204,20 @@ dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl)
 			dns_add_answer(TYPE_AAAA, (uint8_t *) &sa6->sin6_addr, 16, ttl);
 		}
 	}
-	dns_send_answer(iface, to, mdns_hostname_local);
+	dns_send_answer(iface, to, hostname ? hostname : mdns_hostname_local);
 
 	freeifaddrs(ifap);
 }
 
+void
+dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl)
+{
+	struct hostname *h;
+
+	vlist_for_each_element(&hostnames, h, node)
+		dns_reply_a(iface, to, ttl, h->hostname);
+}
+
 static int
 scan_name(const uint8_t *buffer, int len)
 {
@@ -363,14 +372,16 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
 	switch (q->type) {
 	case TYPE_ANY:
 		if (!strcmp(name, mdns_hostname_local)) {
-			dns_reply_a(iface, to, announce_ttl);
+			dns_reply_a(iface, to, announce_ttl, NULL);
+			dns_reply_a_additional(iface, to, announce_ttl);
 			service_reply(iface, to, NULL, NULL, announce_ttl);
 		}
 		break;
 
 	case TYPE_PTR:
 		if (!strcmp(name, C_DNS_SD)) {
-			dns_reply_a(iface, to, announce_ttl);
+			dns_reply_a(iface, to, announce_ttl, NULL);
+			dns_reply_a_additional(iface, to, announce_ttl);
 			service_announce_services(iface, to, announce_ttl);
 		} else {
 			if (name[0] == '_') {
@@ -394,7 +405,7 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
 		if (host)
 			*host = '\0';
 		if (!strcmp(umdns_host_label, name))
-			dns_reply_a(iface, to, announce_ttl);
+			dns_reply_a(iface, to, announce_ttl, NULL);
 		break;
 	};
 }

+ 2 - 1
dns.h

@@ -78,7 +78,8 @@ void dns_send_question(struct interface *iface, struct sockaddr *to,
 void dns_init_answer(void);
 void dns_add_answer(int type, const uint8_t *rdata, uint16_t rdlength, int ttl);
 void dns_send_answer(struct interface *iface, struct sockaddr *to, const char *answer);
-void dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl);
+void dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname);
+void dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl);
 const char* dns_type_string(uint16_t type);
 void dns_handle_packet(struct interface *iface, struct sockaddr *s, uint16_t port, uint8_t *buf, int len);
 

+ 2 - 1
interface.c

@@ -651,7 +651,8 @@ void interface_shutdown(void)
 
 	vlist_for_each_element(&interfaces, iface, node)
 		if (interface_multicast(iface)) {
-			dns_reply_a(iface, NULL, 0);
+			dns_reply_a(iface, NULL, 0, NULL);
+			dns_reply_a_additional(iface, NULL, 0);
 			service_announce_services(iface, NULL, 0);
 		}
 

+ 53 - 0
service.c

@@ -39,6 +39,7 @@ enum {
 	SERVICE_SERVICE,
 	SERVICE_PORT,
 	SERVICE_TXT,
+	SERVICE_HOSTNAME,
 	__SERVICE_MAX,
 };
 
@@ -61,14 +62,20 @@ static const struct blobmsg_policy service_policy[__SERVICE_MAX] = {
 	[SERVICE_SERVICE] = { .name = "service", .type = BLOBMSG_TYPE_STRING },
 	[SERVICE_PORT] = { .name = "port", .type = BLOBMSG_TYPE_INT32 },
 	[SERVICE_TXT] = { .name = "txt", .type = BLOBMSG_TYPE_ARRAY },
+	[SERVICE_HOSTNAME] = { .name = "hostname", .type = BLOBMSG_TYPE_STRING },
 };
 
 static void
 service_update(struct vlist_tree *tree, struct vlist_node *node_new,
 	       struct vlist_node *node_old);
 
+static void
+hostname_update(struct vlist_tree *tree, struct vlist_node *node_new,
+		struct vlist_node *node_old);
+
 static struct blob_buf b;
 static VLIST_TREE(services, avl_strcmp, service_update, false, false);
+VLIST_TREE(hostnames, avl_strcmp, hostname_update, false, false);
 static int service_init_announce;
 
 /**
@@ -210,6 +217,44 @@ service_update(struct vlist_tree *tree, struct vlist_node *node_new,
 	free(s);
 }
 
+static void
+hostname_update(struct vlist_tree *tree, struct vlist_node *node_new,
+		struct vlist_node *node_old)
+{
+	struct interface *iface;
+	struct hostname *h;
+
+	if (!node_old) {
+		h = container_of(node_new, struct hostname, node);
+		vlist_for_each_element(&interfaces, iface, node)
+			dns_reply_a(iface, NULL, announce_ttl, h->hostname);
+		return;
+	}
+
+	h = container_of(node_old, struct hostname, node);
+	if (!node_new)
+		vlist_for_each_element(&interfaces, iface, node)
+			dns_reply_a(iface, NULL, 0, h->hostname);
+
+	free(h);
+}
+
+static void
+service_load_hostname(struct blob_attr *b)
+{
+	struct hostname *h;
+	char *hostname, *d_hostname;
+
+	hostname = blobmsg_get_string(b);
+	h = calloc_a(sizeof(*h), &d_hostname, strlen(hostname) + 1);
+	if (!h)
+		return;
+
+	h->hostname = strcpy(d_hostname, hostname);
+
+	vlist_add(&hostnames, &h->node, h->hostname);
+}
+
 static void
 service_load_blob(struct blob_attr *b)
 {
@@ -223,6 +268,12 @@ service_load_blob(struct blob_attr *b)
 
 	blobmsg_parse(service_policy, ARRAY_SIZE(service_policy),
 		_tb, blobmsg_data(b), blobmsg_data_len(b));
+
+	if (_tb[SERVICE_HOSTNAME]) {
+		service_load_hostname(_tb[SERVICE_HOSTNAME]);
+		return;
+	}
+
 	if (!_tb[SERVICE_PORT] || !_tb[SERVICE_SERVICE])
 		return;
 
@@ -298,6 +349,7 @@ service_init_cb(struct ubus_request *req, int type, struct blob_attr *msg)
 	get_hostname();
 
 	vlist_update(&services);
+	vlist_update(&hostnames);
 	service_load("/etc/umdns/*");
 
 	blob_for_each_attr(cur, msg, rem) {
@@ -342,6 +394,7 @@ service_init_cb(struct ubus_request *req, int type, struct blob_attr *msg)
 		}
 	}
 	vlist_flush(&services);
+	vlist_flush(&hostnames);
 }
 
 void

+ 7 - 0
service.h

@@ -14,6 +14,13 @@
 #ifndef _SERVICE_H__
 #define _SERVICE_H__
 
+struct hostname {
+	struct vlist_node node;
+
+	const char *hostname;
+};
+extern struct vlist_tree hostnames;
+
 extern void service_init(int announce);
 extern void service_cleanup(void);
 extern void service_reply(struct interface *iface, struct sockaddr *to, const char *instance, const char *service_domain, int ttl);