Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions announce.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ announce_timer(struct uloop_timeout *timeout)
/* Fall through */

case STATE_ANNOUNCE:
dns_reply_a(iface, NULL, announce_ttl, NULL);
dns_reply_a_additional(iface, NULL, announce_ttl);
service_announce_services(iface, NULL, announce_ttl);
dns_reply_a(iface, NULL, announce_ttl, NULL, false);
dns_reply_a_additional(iface, NULL, announce_ttl, false);
service_announce_services(iface, NULL, announce_ttl, false);
uloop_timeout_set(timeout, announce_ttl * 800);
break;
}
Expand Down
129 changes: 100 additions & 29 deletions dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ void dns_packet_answer(const char *name, int type, const uint8_t *rdata, uint16_
pkt.h.flags |= cpu_to_be16(0x8400);

a = dns_packet_record_add(sizeof(*a) + rdlength, name);
if (!a)
return;

memset(a, 0, sizeof(*a));
a->type = cpu_to_be16(type);
a->class = cpu_to_be16(1);
Expand Down Expand Up @@ -266,7 +269,7 @@ void dns_query(const char *name, uint16_t type)
}

void
dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname)
dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname, bool append)
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
Expand All @@ -277,7 +280,9 @@ dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *h

getifaddrs(&ifap);

dns_packet_init();
if (!append)
dns_packet_init();

for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, iface->name))
continue;
Expand All @@ -292,16 +297,17 @@ dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *h
}
freeifaddrs(ifap);

dns_packet_send(iface, to, 0, 0);
if(!append)
dns_packet_send(iface, to, 0, 0);
}

void
dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl)
dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl, bool append)
{
struct hostname *h;

vlist_for_each_element(&hostnames, h, node)
dns_reply_a(iface, to, ttl, h->hostname);
dns_reply_a(iface, to, ttl, h->hostname, append);
}

static int
Expand Down Expand Up @@ -484,7 +490,8 @@ match_ip_addresses(char *reverse_ip, char *intf_ip)
}

static void
dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip)
dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip,
bool append)
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in6 *sa6;
Expand All @@ -494,7 +501,10 @@ dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int
int len;

getifaddrs(&ifap);
dns_packet_init();

if (!append)
dns_packet_init();

for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, iface->name))
continue;
Expand All @@ -513,13 +523,16 @@ dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int
}
}
}
dns_packet_send(iface, to, 0, 0);

if (!append)
dns_packet_send(iface, to, 0, 0);

freeifaddrs(ifap);
}

static void
dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip)
dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip,
bool append)
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
Expand All @@ -529,7 +542,10 @@ dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int
int len;

getifaddrs(&ifap);
dns_packet_init();

if (!append)
dns_packet_init();

for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, iface->name))
continue;
Expand All @@ -548,7 +564,8 @@ dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int
}
}
}
dns_packet_send(iface, to, 0, 0);
if (!append)
dns_packet_send(iface, to, 0, 0);

freeifaddrs(ifap);
}
Expand All @@ -572,7 +589,7 @@ is_reverse_dns_query(const char *name, const char *suffix)
}

static void
parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q)
parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q, bool append)
{
int is_unicast = (q->class & CLASS_UNICAST) != 0;
struct sockaddr *to = NULL;
Expand All @@ -581,19 +598,22 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc

/* TODO: Multicast if more than one quarter of TTL has passed */
if (is_unicast) {
to = from;
if (interface_multicast(iface))
iface = interface_get(iface->name, iface->type | SOCKTYPE_BIT_UNICAST);
/* if append is true we have already done this */
if (!append) {
to = from;
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 (!strcasecmp(name, mdns_hostname_local)) {
dns_reply_a(iface, to, announce_ttl, NULL);
dns_reply_a_additional(iface, to, announce_ttl);
service_reply(iface, to, NULL, NULL, announce_ttl, is_unicast);
dns_reply_a(iface, to, announce_ttl, NULL, append);
dns_reply_a_additional(iface, to, announce_ttl, append);
service_reply(iface, to, NULL, NULL, announce_ttl, is_unicast, append);
}
break;

Expand All @@ -603,7 +623,7 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
char name_buf[256];
strcpy(name_buf, name);
*host = '\0';
dns_reply_reverse_ip4_mapping(iface, to, announce_ttl, name_buf, name);
dns_reply_reverse_ip4_mapping(iface, to, announce_ttl, name_buf, name, append);
break;
}

Expand All @@ -612,22 +632,22 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
char name_buf6[256];
strcpy(name_buf6, name);
*host6 = '\0';
dns_reply_reverse_ip6_mapping(iface, to, announce_ttl, name_buf6, name);
dns_reply_reverse_ip6_mapping(iface, to, announce_ttl, name_buf6, name, append);
break;
}

if (!strcasecmp(name, C_DNS_SD)) {
service_announce_services(iface, to, announce_ttl);
service_announce_services(iface, to, announce_ttl, append);
} else {
if (name[0] == '_') {
service_reply(iface, to, NULL, name, announce_ttl, is_unicast);
service_reply(iface, to, NULL, name, announce_ttl, is_unicast, append);
} 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, is_unicast);
service_reply(iface, to, name, dot + 1, announce_ttl, is_unicast, append);
*dot = '.';
}
}
Expand All @@ -640,34 +660,81 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
if (host)
*host = '\0';
if (!strcasecmp(umdns_host_label, name)) {
dns_reply_a(iface, to, announce_ttl, NULL);
dns_reply_a(iface, to, announce_ttl, NULL, append);
} else {
if (host)
*host = '.';
vlist_for_each_element(&hostnames, h, node)
if (!strcasecmp(h->hostname, name))
dns_reply_a(iface, to, announce_ttl, h->hostname);
dns_reply_a(iface, to, announce_ttl, h->hostname, append);
}
break;
};
}

static void
dns_append_questions(uint8_t *orig_buffer, int orig_len)
{
/* Construct original question section */
const struct dns_header *orig_h;
uint8_t *ptr = orig_buffer;
int len = orig_len;

orig_h = dns_consume_header(&ptr, &len);
if (orig_h) {
pkt.h.id = cpu_to_be16(orig_h->id);

uint16_t q_count = be16_to_cpu(orig_h->questions);
while (q_count-- > 0 && len > 0) {
char *qname = dns_consume_name(orig_buffer, orig_len, &ptr, &len);
if (!qname || len < (int)sizeof(struct dns_question))
break;

struct dns_question *q = dns_consume_question(&ptr, &len);
if (!q)
break;

dns_packet_question(qname, q->type);
}
}
}

void
dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port, uint8_t *buffer, int len)
{
struct dns_header *h;
uint8_t *b = buffer;
int rlen = len;
uint8_t orig_buffer[len];
struct sockaddr *to = NULL;
bool append = false;

/* make a copy of the original buffer since it might be needed to construct the answer
* in case the query is received from a one-shot multicast dns querier */
memcpy(orig_buffer, buffer, len);

h = dns_consume_header(&b, &rlen);
if (!h) {
fprintf(stderr, "dropping: bad header\n");
return;
}

if (h->questions && !interface_multicast(iface) && port != MCAST_PORT)
/* silently drop unicast questions that dont originate from port 5353 */
return;
/* legacy querier */
if (port != MCAST_PORT) {
/* aggregate answers and send, instead of sending separately */
append = true;

/* packet construction starts here */
dns_packet_init();

/* add original questions, as outlined by RFC 6762 Section 6.7 */
dns_append_questions(orig_buffer, len);

/* to return a unicast response */
to = from;
if (interface_multicast(iface))
iface = interface_get(iface->name, iface->type | SOCKTYPE_BIT_UNICAST);
}

while (h->questions-- > 0) {
char *name = dns_consume_name(buffer, len, &b, &rlen);
Expand All @@ -685,9 +752,13 @@ dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port,
}

if (!(h->flags & FLAG_RESPONSE))
parse_question(iface, from, name, q);
parse_question(iface, from, name, q, append);
}

/* if append is true, then answers have only been appended to the packet, not sent, so we do that here */
if (append && pkt.h.answers > 0)
dns_packet_send(iface, to, 0, 0);

if (!(h->flags & FLAG_RESPONSE))
return;

Expand Down
4 changes: 2 additions & 2 deletions dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ void dns_query(const char *name, uint16_t type);

void dns_send_question(struct interface *iface, struct sockaddr *to,
const char *question, int type, int multicast);
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);
void dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname, bool append);
void dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl, bool append);
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);

Expand Down
6 changes: 3 additions & 3 deletions interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,9 +666,9 @@ void interface_shutdown(void)

vlist_for_each_element(&interfaces, iface, node)
if (interface_multicast(iface)) {
dns_reply_a(iface, NULL, 0, NULL);
dns_reply_a_additional(iface, NULL, 0);
service_announce_services(iface, NULL, 0);
dns_reply_a(iface, NULL, 0, NULL, false);
dns_reply_a_additional(iface, NULL, 0, false);
service_announce_services(iface, NULL, 0, false);
}

for (size_t i = 0; i < ARRAY_SIZE(ufd); i++) {
Expand Down
Loading