[LEDE-DEV] [PATCH mdns 2/3] Use unicast IP address when sending unicast service reply

Rafał Miłecki zajec5 at gmail.com
Tue Feb 14 03:18:05 PST 2017


From: Rafał Miłecki <rafal at milecki.pl>

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 at milecki.pl>
---
 announce.c  |  2 +-
 dns.c       | 18 ++++++++++++------
 interface.c |  2 +-
 service.c   | 20 ++++++++++----------
 service.h   |  4 ++--
 5 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/announce.c b/announce.c
index f04a600..63009ee 100644
--- a/announce.c
+++ b/announce.c
@@ -66,7 +66,7 @@ announce_timer(struct uloop_timeout *timeout)
 
 		case STATE_ANNOUNCE:
 			dns_reply_a(iface, 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 707d54c..529aa25 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);
+			service_reply(iface, to, NULL, announce_ttl);
 			dns_reply_a(iface, 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;
 
@@ -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 55706bf..64a8fb9 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, 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 ca84da2..cda9188 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 8bc9ba9..899c77a 100644
--- a/service.h
+++ b/service.h
@@ -17,7 +17,7 @@
 extern 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.11.0




More information about the Lede-dev mailing list