From c78cfb1475f755c85949882e0d9d857a800348a1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 14 Feb 2017 12:18:05 +0100 Subject: [PATCH] Use unicast IP address when sending unicast service reply MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit For each protocol (IPv4 and IPv6) we have two interfaces (sockets): one for unicast and one for multicast. If we noticed CLASS_UNICAST in the multicast query we were switching to unicast interface for sending reply. The problem was not passing destination IP address. It was resulting in sending packet to multicast IP using unicast interface. As we don't set IP_MULTICAST_TTL / IPV6_MULTICAST_HOPS for unicast ones TTL was 1 and packets were ignored. Signed-off-by: Rafał Miłecki --- announce.c | 2 +- dns.c | 22 ++++++++++++++-------- interface.c | 2 +- service.c | 20 ++++++++++---------- service.h | 4 ++-- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/announce.c b/announce.c index 695c66e..fed1b21 100644 --- a/announce.c +++ b/announce.c @@ -66,7 +66,7 @@ announce_timer(struct uloop_timeout *timeout) case STATE_ANNOUNCE: dns_reply_a(iface, NULL, announce_ttl); - service_announce_services(iface, 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 a09b0ec..4c3dbf9 100644 --- a/dns.c +++ b/dns.c @@ -349,26 +349,32 @@ parse_answer(struct interface *iface, uint8_t *buffer, int len, uint8_t **b, int } static void -parse_question(struct interface *iface, char *name, struct dns_question *q) +parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q) { + struct sockaddr *to; char *host; - if ((q->class & CLASS_UNICAST) && iface->multicast) + /* TODO: Multicast if more than one quarter of TTL has passed */ + if ((q->class & CLASS_UNICAST) && iface->multicast) { iface = iface->peer; + to = from; + } else { + to = NULL; + } DBG(1, "Q -> %s %s\n", dns_type_string(q->type), name); switch (q->type) { case TYPE_ANY: if (!strcmp(name, mdns_hostname_local)) { - service_reply(iface, NULL, announce_ttl); - dns_reply_a(iface, NULL, announce_ttl); + dns_reply_a(iface, to, announce_ttl); + service_reply(iface, to, NULL, announce_ttl); } break; case TYPE_PTR: if (!strcmp(name, sdudp)) { - service_announce_services(iface, announce_ttl); + service_announce_services(iface, to, announce_ttl); } else { /* First dot separates instance name from the rest */ char *dot = strchr(name, '.'); @@ -378,7 +384,7 @@ parse_question(struct interface *iface, char *name, struct dns_question *q) /* Make sure it's query for the instance name we use */ if (len && len == strlen(mdns_hostname) && !strncmp(name, mdns_hostname, len)) - service_reply(iface, dot + 1, announce_ttl); + service_reply(iface, to, dot + 1, announce_ttl); } break; @@ -388,7 +394,7 @@ parse_question(struct interface *iface, char *name, struct dns_question *q) if (host) *host = '\0'; if (!strcmp(mdns_hostname, name)) - dns_reply_a(iface, NULL, announce_ttl); + dns_reply_a(iface, to, announce_ttl); break; }; } @@ -426,7 +432,7 @@ dns_handle_packet(struct interface *iface, struct sockaddr *s, uint16_t port, ui } if (!(h->flags & FLAG_RESPONSE)) - parse_question(iface, name, q); + parse_question(iface, s, name, q); } if (!(h->flags & FLAG_RESPONSE)) diff --git a/interface.c b/interface.c index 69de071..1cc9499 100644 --- a/interface.c +++ b/interface.c @@ -637,7 +637,7 @@ void interface_shutdown(void) vlist_for_each_element(&interfaces, iface, node) if (iface->fd.fd > 0 && iface->multicast) { dns_reply_a(iface, NULL, 0); - service_announce_services(iface, 0); + service_announce_services(iface, NULL, 0); } vlist_for_each_element(&interfaces, iface, node) interface_close(iface); diff --git a/service.c b/service.c index 9ee01e6..075ac15 100644 --- a/service.c +++ b/service.c @@ -117,7 +117,7 @@ service_timeout(struct service *s) } static void -service_reply_single(struct interface *iface, struct service *s, int ttl, int force) +service_reply_single(struct interface *iface, struct sockaddr *to, struct service *s, int ttl, int force) { const char *host = service_name(s->service); char *service = strstr(host, "._"); @@ -133,28 +133,28 @@ service_reply_single(struct interface *iface, struct service *s, int ttl, int fo dns_init_answer(); service_add_ptr(service_name(s->service), ttl); - dns_send_answer(iface, NULL, service); + dns_send_answer(iface, to, service); dns_init_answer(); service_add_srv(s, ttl); if (s->txt && s->txt_len) dns_add_answer(TYPE_TXT, (uint8_t *) s->txt, s->txt_len, ttl); - dns_send_answer(iface, NULL, host); + dns_send_answer(iface, to, host); } void -service_reply(struct interface *iface, const char *match, int ttl) +service_reply(struct interface *iface, struct sockaddr *to, const char *match, int ttl) { struct service *s; vlist_for_each_element(&services, s, node) { if (!match || !strcmp(s->service, match)) - service_reply_single(iface, s, ttl, 0); + service_reply_single(iface, to, s, ttl, 0); } } void -service_announce_services(struct interface *iface, int ttl) +service_announce_services(struct interface *iface, struct sockaddr *to, int ttl) { struct service *s; @@ -163,9 +163,9 @@ service_announce_services(struct interface *iface, int ttl) if (ttl) { dns_init_answer(); service_add_ptr(s->service, ttl); - dns_send_answer(iface, NULL, sdudp); + dns_send_answer(iface, to, sdudp); } - service_reply_single(iface, s, ttl, 0); + service_reply_single(iface, to, s, ttl, 0); } } @@ -181,7 +181,7 @@ service_update(struct vlist_tree *tree, struct vlist_node *node_new, if (service_init_announce) vlist_for_each_element(&interfaces, iface, node) { s->t = 0; - service_reply_single(iface, s, announce_ttl, 1); + service_reply_single(iface, NULL, s, announce_ttl, 1); } return; } @@ -189,7 +189,7 @@ service_update(struct vlist_tree *tree, struct vlist_node *node_new, s = container_of(node_old, struct service, node); if (!node_new && service_init_announce) vlist_for_each_element(&interfaces, iface, node) - service_reply_single(iface, s, 0, 1); + service_reply_single(iface, NULL, s, 0, 1); free(s); } diff --git a/service.h b/service.h index b46b521..67a425a 100644 --- a/service.h +++ b/service.h @@ -17,7 +17,7 @@ extern const char *sdudp; extern void service_init(int announce); extern void service_cleanup(void); -extern void service_reply(struct interface *iface, const char *match, int ttl); -extern void service_announce_services(struct interface *iface, int ttl); +extern void service_reply(struct interface *iface, struct sockaddr *to, const char *match, int ttl); +extern void service_announce_services(struct interface *iface, struct sockaddr *to, int ttl); #endif -- 2.30.2