From 3b341f41834e025715a92fdb384106b39b7216d3 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 27 Nov 2023 07:47:17 +0100 Subject: [PATCH] add the ability to announce additional hostnames Signed-off-by: John Crispin --- announce.c | 3 ++- dns.c | 21 ++++++++++++++++----- dns.h | 3 ++- interface.c | 3 ++- service.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ service.h | 7 +++++++ 6 files changed, 82 insertions(+), 8 deletions(-) diff --git a/announce.c b/announce.c index 3c8ea16..a562277 100644 --- a/announce.c +++ b/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; diff --git a/dns.c b/dns.c index 2ebb624..2b5a390 100644 --- a/dns.c +++ b/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; }; } diff --git a/dns.h b/dns.h index 91570bd..39a1a51 100644 --- a/dns.h +++ b/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); diff --git a/interface.c b/interface.c index 5b1591c..ca4b0b3 100644 --- a/interface.c +++ b/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); } diff --git a/service.c b/service.c index bd9f985..b693b31 100644 --- a/service.c +++ b/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 diff --git a/service.h b/service.h index db8f374..9dea1f6 100644 --- a/service.h +++ b/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); -- 2.30.2