Use unicast IP address when sending unicast service reply
authorRafał Miłecki <rafal@milecki.pl>
Tue, 14 Feb 2017 11:18:05 +0000 (12:18 +0100)
committerRafał Miłecki <rafal@milecki.pl>
Wed, 15 Feb 2017 10:11:53 +0000 (11:11 +0100)
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 <rafal@milecki.pl>
announce.c
dns.c
interface.c
service.c
service.h

index 695c66e..fed1b21 100644 (file)
@@ -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 (file)
--- 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))
index 69de071..1cc9499 100644 (file)
@@ -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);
index 9ee01e6..075ac15 100644 (file)
--- 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);
 }
 
index b46b521..67a425a 100644 (file)
--- 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