}
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_A, (uint8_t *) &sa->sin_addr, 4, ttl);
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
- uint8_t ll_prefix[] = {0xfe, 0x80 };
sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
- if (!memcmp(&sa6->sin6_addr, &ll_prefix, 2))
- dns_add_answer(TYPE_AAAA, (uint8_t *) &sa6->sin6_addr, 16, 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)
{
if (IS_COMPRESSED(l))
return offset + 2;
+ if (l + 1 > len) return -1;
len -= l + 1;
offset += l + 1;
buffer += l + 1;
dns_consume_header(uint8_t **data, int *len)
{
struct dns_header *h = (struct dns_header *) *data;
- uint16_t *swap = (uint16_t *) h;
- int endianess = 6;
if (*len < sizeof(struct dns_header))
return NULL;
- while (endianess--) {
- *swap = be16_to_cpu(*swap);
- swap++;
- }
+ h->id = be16_to_cpu(h->id);
+ h->flags = be16_to_cpu(h->flags);
+ h->questions = be16_to_cpu(h->questions);
+ h->answers = be16_to_cpu(h->answers);
+ h->authority = be16_to_cpu(h->authority);
+ h->additional = be16_to_cpu(h->additional);
*len -= sizeof(struct dns_header);
*data += sizeof(struct dns_header);
dns_consume_question(uint8_t **data, int *len)
{
struct dns_question *q = (struct dns_question *) *data;
- uint16_t *swap = (uint16_t *) q;
- int endianess = 2;
if (*len < sizeof(struct dns_question))
return NULL;
- while (endianess--) {
- *swap = be16_to_cpu(*swap);
- swap++;
- }
+ q->type = be16_to_cpu(q->type);
+ q->class = be16_to_cpu(q->class);
*len -= sizeof(struct dns_question);
*data += sizeof(struct dns_question);
struct dns_answer *a;
uint8_t *rdata;
- if (!name) {
+ if (!name || *rlen < 0) {
fprintf(stderr, "dropping: bad question\n");
return -1;
}
/* TODO: Multicast if more than one quarter of TTL has passed */
if (q->class & CLASS_UNICAST) {
to = from;
- if (iface->multicast)
- iface = iface->peer;
+ if (interface_multicast(iface))
+ iface = interface_get(iface->name, iface->type | SOCKTYPE_BIT_UNICAST);
}
DBG(1, "Q -> %s %s\n", dns_type_string(q->type), name);
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 {
- /* First dot separates instance name from the rest */
- char *dot = strchr(name, '.');
- /* Length of queried instance */
- size_t len = dot ? dot - name : 0;
-
- /* Make sure it's query for the instance name we use */
- if (len && len == strlen(umdns_host_label) &&
- !strncmp(name, umdns_host_label, len))
- service_reply(iface, to, NULL, dot + 1, announce_ttl);
+ if (name[0] == '_') {
+ service_reply(iface, to, NULL, name, announce_ttl);
+ } else {
+ /* First dot separates instance name from the rest */
+ char *dot = strchr(name, '.');
+
+ if (dot) {
+ *dot = '\0';
+ service_reply(iface, to, name, dot + 1, announce_ttl);
+ *dot = '.';
+ }
+ }
}
break;
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;
};
}
return;
}
- if (h->questions && !iface->multicast && port != MCAST_PORT)
+ if (h->questions && !interface_multicast(iface) && port != MCAST_PORT)
/* silently drop unicast questions that dont originate from port 5353 */
return;
char *name = dns_consume_name(buffer, len, &b, &rlen);
struct dns_question *q;
- if (!name) {
+ if (!name || rlen < 0) {
fprintf(stderr, "dropping: bad name\n");
return;
}