/* 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;
}
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;
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)
{
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] == '_') {
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;
};
}
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);
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);
}
SERVICE_SERVICE,
SERVICE_PORT,
SERVICE_TXT,
+ SERVICE_HOSTNAME,
__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;
/**
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)
{
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;
get_hostname();
vlist_update(&services);
+ vlist_update(&hostnames);
service_load("/etc/umdns/*");
blob_for_each_attr(cur, msg, rem) {
}
}
vlist_flush(&services);
+ vlist_flush(&hostnames);
}
void
#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);