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 695c66effa9d56109dc97d8090ef71f525df3bc5..fed1b212fe2fb5a754a7429a5a9c7f8a5179c9e3 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 a09b0ec74d8f230b66b709fd0e9ba40c2a1bcc47..4c3dbf92f6c1e4598d5e07d39ea91b351ad5e190 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 69de071614925309fa5498555569188d01953cbb..1cc9499d95f33a7bc4b3a7b2ffffb5fe7eb3e4dc 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 9ee01e6a4bef3e2807dc8f4d0762533182ba67f7..075ac15325fcc927cb9368eaedfe2b229cb86230 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 b46b52108b12311054583d547177e09a9f7f11d4..67a425abbae4feca226ab55bce255f22094295e6 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