1 /** @file
2 * @brief mDNS responder
3 *
4 * This listens to mDNS queries and responds to them.
5 */
6
7 /*
8 * Copyright (c) 2017 Intel Corporation
9 * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
10 * Copyright (c) 2024 Nordic Semiconductor ASA
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 */
14
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(net_mdns_responder, CONFIG_MDNS_RESPONDER_LOG_LEVEL);
17
18 #include <zephyr/kernel.h>
19 #include <zephyr/init.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <errno.h>
23 #include <stdlib.h>
24
25 #include <zephyr/net/mld.h>
26 #include <zephyr/net/net_core.h>
27 #include <zephyr/net/net_ip.h>
28 #include <zephyr/net/net_pkt.h>
29 #include <zephyr/net/dns_resolve.h>
30 #include <zephyr/net/socket_service.h>
31 #include <zephyr/net/igmp.h>
32
33 #include "dns_sd.h"
34 #include "dns_pack.h"
35 #include "ipv6.h"
36 #include "../../ip/net_stats.h"
37
38 #include "net_private.h"
39
40 /*
41 * GCC complains about struct sockaddr accesses due to the various
42 * address-family-specific variants being of differing sizes. Let's not
43 * mess with code (which looks correct), just silence the compiler.
44 */
45 #ifdef __GNUC__
46 #pragma GCC diagnostic ignored "-Wpragmas"
47 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
48 #pragma GCC diagnostic ignored "-Warray-bounds"
49 #pragma GCC diagnostic ignored "-Wstringop-overread"
50 #endif
51
52 extern void dns_dispatcher_svc_handler(struct net_socket_service_event *pev);
53
54 #define MDNS_LISTEN_PORT 5353
55
56 #define MDNS_TTL CONFIG_MDNS_RESPONDER_TTL /* In seconds */
57
58 #if defined(CONFIG_NET_IPV4)
59 static struct mdns_responder_context v4_ctx[MAX_IPV4_IFACE_COUNT];
60
61 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(v4_svc, dns_dispatcher_svc_handler,
62 MDNS_MAX_IPV4_IFACE_COUNT);
63 #endif
64
65 #if defined(CONFIG_NET_IPV6)
66 static struct mdns_responder_context v6_ctx[MAX_IPV6_IFACE_COUNT];
67
68 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(v6_svc, dns_dispatcher_svc_handler,
69 MDNS_MAX_IPV6_IFACE_COUNT);
70 #endif
71
72 static struct net_mgmt_event_callback mgmt_cb;
73 static const struct dns_sd_rec *external_records;
74 static size_t external_records_count;
75
76 #define BUF_ALLOC_TIMEOUT K_MSEC(100)
77
78 #ifndef CONFIG_NET_TEST
79 static int setup_dst_addr(int sock, sa_family_t family,
80 struct sockaddr *dst, socklen_t *dst_len);
81 #endif /* CONFIG_NET_TEST */
82
83 #define DNS_RESOLVER_MIN_BUF 2
84 #define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + \
85 CONFIG_MDNS_RESOLVER_ADDITIONAL_BUF_CTR)
86
87 NET_BUF_POOL_DEFINE(mdns_msg_pool, DNS_RESOLVER_BUF_CTR,
88 DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL);
89
create_ipv6_addr(struct sockaddr_in6 * addr)90 static void create_ipv6_addr(struct sockaddr_in6 *addr)
91 {
92 addr->sin6_family = AF_INET6;
93 addr->sin6_port = htons(MDNS_LISTEN_PORT);
94
95 /* Well known IPv6 ff02::fb address */
96 net_ipv6_addr_create(&addr->sin6_addr,
97 0xff02, 0, 0, 0, 0, 0, 0, 0x00fb);
98 }
99
create_ipv4_addr(struct sockaddr_in * addr)100 static void create_ipv4_addr(struct sockaddr_in *addr)
101 {
102 addr->sin_family = AF_INET;
103 addr->sin_port = htons(MDNS_LISTEN_PORT);
104
105 /* Well known IPv4 224.0.0.251 address */
106 addr->sin_addr.s_addr = htonl(0xE00000FB);
107 }
108
mdns_iface_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)109 static void mdns_iface_event_handler(struct net_mgmt_event_callback *cb,
110 uint32_t mgmt_event, struct net_if *iface)
111
112 {
113 if (mgmt_event == NET_EVENT_IF_UP) {
114 #if defined(CONFIG_NET_IPV4)
115 ARRAY_FOR_EACH(v4_ctx, i) {
116 int ret = net_ipv4_igmp_join(iface,
117 &net_sin(&v4_ctx[i].dispatcher.local_addr)->sin_addr,
118 NULL);
119 if (ret < 0) {
120 NET_DBG("Cannot add IPv4 multicast address to iface %d",
121 net_if_get_by_iface(iface));
122 }
123 }
124 #endif /* defined(CONFIG_NET_IPV4) */
125 }
126 }
127
set_ttl_hop_limit(int sock,int level,int option,int new_limit)128 static int set_ttl_hop_limit(int sock, int level, int option, int new_limit)
129 {
130 return zsock_setsockopt(sock, level, option, &new_limit, sizeof(new_limit));
131 }
132
setup_dst_addr(int sock,sa_family_t family,struct sockaddr * dst,socklen_t * dst_len)133 int setup_dst_addr(int sock, sa_family_t family,
134 struct sockaddr *dst, socklen_t *dst_len)
135 {
136 int ret;
137
138 if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
139 create_ipv4_addr(net_sin(dst));
140 *dst_len = sizeof(struct sockaddr_in);
141
142 ret = set_ttl_hop_limit(sock, IPPROTO_IP, IP_MULTICAST_TTL, 255);
143 if (ret < 0) {
144 NET_DBG("Cannot set %s multicast %s (%d)", "IPv4", "TTL", ret);
145 }
146 } else if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
147 create_ipv6_addr(net_sin6(dst));
148 *dst_len = sizeof(struct sockaddr_in6);
149
150 ret = set_ttl_hop_limit(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255);
151 if (ret < 0) {
152 NET_DBG("Cannot set %s multicast %s (%d)", "IPv6", "hoplimit", ret);
153 }
154 } else {
155 return -EPFNOSUPPORT;
156 }
157
158 return 0;
159 }
160
get_socket(sa_family_t family)161 static int get_socket(sa_family_t family)
162 {
163 int ret;
164
165 ret = zsock_socket(family, SOCK_DGRAM, IPPROTO_UDP);
166 if (ret < 0) {
167 ret = -errno;
168 NET_DBG("Cannot get socket (%d)", ret);
169 }
170
171 return ret;
172 }
173
setup_dns_hdr(uint8_t * buf,uint16_t answers)174 static void setup_dns_hdr(uint8_t *buf, uint16_t answers)
175 {
176 uint16_t offset;
177 uint16_t flags;
178
179 /* See RFC 1035, ch 4.1.1 for header details */
180
181 flags = BIT(15); /* This is response */
182 flags |= BIT(10); /* Authoritative Answer */
183
184 UNALIGNED_PUT(0, (uint16_t *)(buf)); /* Identifier, RFC 6762 ch 18.1 */
185 offset = DNS_HEADER_ID_LEN;
186
187 UNALIGNED_PUT(htons(flags), (uint16_t *)(buf+offset));
188 offset += DNS_HEADER_FLAGS_LEN;
189
190 UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
191 offset += DNS_QDCOUNT_LEN;
192
193 UNALIGNED_PUT(htons(answers), (uint16_t *)(buf + offset));
194 offset += DNS_ANCOUNT_LEN;
195
196 UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
197 offset += DNS_NSCOUNT_LEN;
198
199 UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
200 }
201
add_answer(struct net_buf * query,enum dns_rr_type qtype,uint32_t ttl,uint16_t addr_len,uint8_t * addr)202 static void add_answer(struct net_buf *query, enum dns_rr_type qtype,
203 uint32_t ttl, uint16_t addr_len, uint8_t *addr)
204 {
205 char *dot = query->data + DNS_MSG_HEADER_SIZE;
206 char *prev = NULL;
207 uint16_t offset;
208
209 while ((dot = strchr(dot, '.'))) {
210 if (!prev) {
211 prev = dot++;
212 continue;
213 }
214
215 *prev = dot - prev - 1;
216 prev = dot++;
217 }
218
219 if (prev) {
220 *prev = strlen(prev) - 1;
221 }
222
223 /* terminator byte (0x00) */
224 query->len += 1;
225
226 offset = DNS_MSG_HEADER_SIZE + query->len;
227 UNALIGNED_PUT(htons(qtype), (uint16_t *)(query->data+offset));
228
229 /* Bit 15 tells to flush the cache */
230 offset += DNS_QTYPE_LEN;
231 UNALIGNED_PUT(htons(DNS_CLASS_IN | BIT(15)),
232 (uint16_t *)(query->data+offset));
233
234
235 offset += DNS_QCLASS_LEN;
236 UNALIGNED_PUT(htonl(ttl), query->data + offset);
237
238 offset += DNS_TTL_LEN;
239 UNALIGNED_PUT(htons(addr_len), query->data + offset);
240
241 offset += DNS_RDLENGTH_LEN;
242 memcpy(query->data + offset, addr, addr_len);
243 }
244
create_answer(int sock,struct net_buf * query,enum dns_rr_type qtype,uint16_t addr_len,uint8_t * addr)245 static int create_answer(int sock,
246 struct net_buf *query,
247 enum dns_rr_type qtype,
248 uint16_t addr_len, uint8_t *addr)
249 {
250 /* Prepare the response into the query buffer: move the name
251 * query buffer has to get enough free space: dns_hdr + answer
252 */
253 if ((net_buf_max_len(query) - query->len) < (DNS_MSG_HEADER_SIZE +
254 DNS_QTYPE_LEN + DNS_QCLASS_LEN +
255 DNS_TTL_LEN + DNS_RDLENGTH_LEN +
256 addr_len)) {
257 return -ENOBUFS;
258 }
259
260 memmove(query->data + DNS_MSG_HEADER_SIZE, query->data, query->len);
261
262 setup_dns_hdr(query->data, 1);
263
264 add_answer(query, qtype, MDNS_TTL, addr_len, addr);
265
266 query->len += DNS_MSG_HEADER_SIZE +
267 DNS_QTYPE_LEN + DNS_QCLASS_LEN +
268 DNS_TTL_LEN + DNS_RDLENGTH_LEN + addr_len;
269
270 return 0;
271 }
272
send_response(int sock,sa_family_t family,struct sockaddr * src_addr,size_t addrlen,struct net_buf * query,enum dns_rr_type qtype)273 static int send_response(int sock,
274 sa_family_t family,
275 struct sockaddr *src_addr,
276 size_t addrlen,
277 struct net_buf *query,
278 enum dns_rr_type qtype)
279 {
280 struct net_if *iface;
281 socklen_t dst_len;
282 int ret;
283 COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6),
284 (struct sockaddr_in6), (struct sockaddr_in)) dst;
285
286 ret = setup_dst_addr(sock, family, (struct sockaddr *)&dst, &dst_len);
287 if (ret < 0) {
288 NET_DBG("unable to set up the response address");
289 return ret;
290 }
291
292 if (family == AF_INET6) {
293 iface = net_if_ipv6_select_src_iface(&net_sin6(src_addr)->sin6_addr);
294 } else {
295 iface = net_if_ipv4_select_src_iface(&net_sin(src_addr)->sin_addr);
296 }
297
298 if (IS_ENABLED(CONFIG_NET_IPV4) && qtype == DNS_RR_TYPE_A) {
299 const struct in_addr *addr;
300
301 if (family == AF_INET) {
302 addr = net_if_ipv4_select_src_addr(iface,
303 &net_sin(src_addr)->sin_addr);
304 } else {
305 struct sockaddr_in tmp_addr;
306
307 create_ipv4_addr(&tmp_addr);
308 addr = net_if_ipv4_select_src_addr(iface, &tmp_addr.sin_addr);
309 }
310
311 ret = create_answer(sock, query, qtype, sizeof(struct in_addr), (uint8_t *)addr);
312 if (ret != 0) {
313 return ret;
314 }
315 } else if (IS_ENABLED(CONFIG_NET_IPV6) && qtype == DNS_RR_TYPE_AAAA) {
316 const struct in6_addr *addr;
317
318 if (family == AF_INET6) {
319 addr = net_if_ipv6_select_src_addr(iface,
320 &net_sin6(src_addr)->sin6_addr);
321 } else {
322 struct sockaddr_in6 tmp_addr;
323
324 create_ipv6_addr(&tmp_addr);
325 addr = net_if_ipv6_select_src_addr(iface, &tmp_addr.sin6_addr);
326 }
327
328 ret = create_answer(sock, query, qtype, sizeof(struct in6_addr), (uint8_t *)addr);
329 if (ret != 0) {
330 return -ENOMEM;
331 }
332 } else {
333 /* TODO: support also service PTRs */
334 return -EINVAL;
335 }
336
337 ret = zsock_sendto(sock, query->data, query->len, 0,
338 (struct sockaddr *)&dst, dst_len);
339 if (ret < 0) {
340 NET_DBG("Cannot send %s reply (%d)", "mDNS", ret);
341 } else {
342 net_stats_update_dns_sent(iface);
343 }
344
345 return ret;
346 }
347
send_sd_response(int sock,sa_family_t family,struct sockaddr * src_addr,size_t addrlen,struct dns_msg_t * dns_msg,struct net_buf * result)348 static void send_sd_response(int sock,
349 sa_family_t family,
350 struct sockaddr *src_addr,
351 size_t addrlen,
352 struct dns_msg_t *dns_msg,
353 struct net_buf *result)
354 {
355 struct net_if *iface;
356 socklen_t dst_len;
357 int ret;
358 const struct dns_sd_rec *record;
359 /* filter must be zero-initialized for "wildcard" port */
360 struct dns_sd_rec filter = {0};
361 bool service_type_enum = false;
362 const struct in6_addr *addr6 = NULL;
363 const struct in_addr *addr4 = NULL;
364 char instance_buf[DNS_SD_INSTANCE_MAX_SIZE + 1];
365 char service_buf[DNS_SD_SERVICE_MAX_SIZE + 1];
366 /* Depending on segment count in the query, third buffer could hold
367 * either protocol or domain, use larger size.
368 */
369 char proto_buf[DNS_SD_DOMAIN_MAX_SIZE + 1];
370 char domain_buf[DNS_SD_DOMAIN_MAX_SIZE + 1];
371 char *label[4];
372 size_t size[] = {
373 ARRAY_SIZE(instance_buf),
374 ARRAY_SIZE(service_buf),
375 ARRAY_SIZE(proto_buf),
376 ARRAY_SIZE(domain_buf),
377 };
378 size_t n = ARRAY_SIZE(label);
379 size_t rec_num;
380 size_t ext_rec_num = external_records_count;
381 COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6),
382 (struct sockaddr_in6), (struct sockaddr_in)) dst;
383
384 BUILD_ASSERT(ARRAY_SIZE(label) == ARRAY_SIZE(size), "");
385
386 /*
387 * work around for bug in compliance scripts which say that the array
388 * should be static const (incorrect)
389 */
390 label[0] = instance_buf;
391 label[1] = service_buf;
392 label[2] = proto_buf;
393 label[3] = domain_buf;
394
395 ret = setup_dst_addr(sock, family, (struct sockaddr *)&dst, &dst_len);
396 if (ret < 0) {
397 NET_DBG("unable to set up the response address");
398 return;
399 }
400
401 if (family == AF_INET6) {
402 iface = net_if_ipv6_select_src_iface(&net_sin6(src_addr)->sin6_addr);
403 } else {
404 iface = net_if_ipv4_select_src_iface(&net_sin(src_addr)->sin_addr);
405 }
406
407 if (IS_ENABLED(CONFIG_NET_IPV4)) {
408 /* Look up the local IPv4 address */
409 if (family == AF_INET) {
410 addr4 = net_if_ipv4_select_src_addr(iface,
411 &net_sin(src_addr)->sin_addr);
412 } else {
413 struct sockaddr_in tmp_addr;
414
415 create_ipv4_addr(&tmp_addr);
416 addr4 = net_if_ipv4_select_src_addr(iface, &tmp_addr.sin_addr);
417 }
418 }
419
420 if (IS_ENABLED(CONFIG_NET_IPV6)) {
421 /* Look up the local IPv6 address */
422 if (family == AF_INET6) {
423 addr6 = net_if_ipv6_select_src_addr(iface,
424 &net_sin6(src_addr)->sin6_addr);
425 } else {
426 struct sockaddr_in6 tmp_addr;
427
428 create_ipv6_addr(&tmp_addr);
429 addr6 = net_if_ipv6_select_src_addr(iface, &tmp_addr.sin6_addr);
430 }
431 }
432
433 ret = dns_sd_query_extract(dns_msg->msg,
434 dns_msg->msg_size, &filter, label, size, &n);
435 if (ret < 0) {
436 NET_DBG("unable to extract query (%d)", ret);
437 return;
438 }
439
440 if (IS_ENABLED(CONFIG_MDNS_RESPONDER_DNS_SD_SERVICE_TYPE_ENUMERATION)
441 && dns_sd_is_service_type_enumeration(&filter)) {
442
443 /*
444 * RFC 6763, Section 9
445 *
446 * A DNS query for PTR records with the name
447 * "_services._dns-sd._udp.<Domain>" yields a set of PTR records,
448 * where the rdata of each PTR record is the two-label <Service> name,
449 * plus the same domain, e.g., "_http._tcp.<Domain>".
450 */
451 dns_sd_create_wildcard_filter(&filter);
452 service_type_enum = true;
453 }
454
455 DNS_SD_COUNT(&rec_num);
456
457 while (rec_num > 0 || ext_rec_num > 0) {
458 /*
459 * The loop will always iterate over all entries, it can be done
460 * backwards for simplicity
461 */
462 if (rec_num > 0) {
463 DNS_SD_GET(rec_num - 1, &record);
464 rec_num--;
465 } else {
466 record = &external_records[ext_rec_num - 1];
467 ext_rec_num--;
468 }
469
470 /* Checks validity and then compare */
471 if (dns_sd_rec_match(record, &filter)) {
472 NET_DBG("matched query: %s.%s.%s.%s port: %u",
473 record->instance, record->service,
474 record->proto, record->domain,
475 ntohs(*(record->port)));
476
477 /* Construct the response */
478 if (service_type_enum) {
479 ret = dns_sd_handle_service_type_enum(record, addr4, addr6,
480 result->data, net_buf_max_len(result));
481 if (ret < 0) {
482 NET_DBG("dns_sd_handle_service_type_enum() failed (%d)",
483 ret);
484 continue;
485 }
486 } else {
487 ret = dns_sd_handle_ptr_query(record, addr4, addr6,
488 result->data, net_buf_max_len(result));
489 if (ret < 0) {
490 NET_DBG("dns_sd_handle_ptr_query() failed (%d)", ret);
491 continue;
492 }
493 }
494
495 result->len = ret;
496
497 /* Send the response */
498 ret = zsock_sendto(sock, result->data, result->len, 0,
499 (struct sockaddr *)&dst, dst_len);
500 if (ret < 0) {
501 NET_DBG("Cannot send %s reply (%d)", "mDNS", ret);
502 continue;
503 } else {
504 net_stats_update_dns_sent(iface);
505 }
506 }
507 }
508 }
509
dns_read(int sock,struct net_buf * dns_data,size_t len,struct sockaddr * src_addr,size_t addrlen)510 static int dns_read(int sock,
511 struct net_buf *dns_data,
512 size_t len,
513 struct sockaddr *src_addr,
514 size_t addrlen)
515 {
516 /* Helper struct to track the dns msg received from the server */
517 const char *hostname = net_hostname_get();
518 int hostname_len = strlen(hostname);
519 int family = src_addr->sa_family;
520 struct net_buf *result;
521 struct dns_msg_t dns_msg;
522 int data_len;
523 int queries;
524 int ret;
525
526 data_len = MIN(len, DNS_RESOLVER_MAX_BUF_SIZE);
527
528 /* Store the DNS query name into a temporary net_buf, which will be
529 * eventually used to send a response
530 */
531 result = net_buf_alloc(&mdns_msg_pool, BUF_ALLOC_TIMEOUT);
532 if (!result) {
533 ret = -ENOMEM;
534 goto quit;
535 }
536
537 dns_msg.msg = dns_data->data;
538 dns_msg.msg_size = data_len;
539
540 ret = mdns_unpack_query_header(&dns_msg, NULL);
541 if (ret < 0) {
542 goto quit;
543 }
544
545 queries = ret;
546
547 NET_DBG("Received %d %s from %s", queries,
548 queries > 1 ? "queries" : "query",
549 net_sprint_addr(family,
550 family == AF_INET ?
551 (const void *)&net_sin(src_addr)->sin_addr :
552 (const void *)&net_sin6(src_addr)->sin6_addr));
553
554 do {
555 enum dns_rr_type qtype;
556 enum dns_class qclass;
557 uint8_t *lquery;
558
559 (void)memset(result->data, 0, net_buf_tailroom(result));
560 result->len = 0U;
561
562 ret = dns_unpack_query(&dns_msg, result, &qtype, &qclass);
563 if (ret < 0) {
564 goto quit;
565 }
566
567 /* Handle only .local queries */
568 lquery = strrchr(result->data + 1, '.');
569 if (!lquery || memcmp(lquery, (const void *){ ".local" }, 7)) {
570 continue;
571 }
572
573 NET_DBG("[%d] query %s/%s label %s (%d bytes)", queries,
574 dns_qtype_to_str(qtype), "IN",
575 result->data, ret);
576
577 /* If the query matches to our hostname, then send reply.
578 * We skip the first dot, and make sure there is dot after
579 * matching hostname.
580 */
581 if (!strncasecmp(hostname, result->data + 1, hostname_len) &&
582 (result->len - 1) >= hostname_len &&
583 &(result->data + 1)[hostname_len] == lquery) {
584 NET_DBG("%s query to our hostname %s.local", "mDNS",
585 hostname);
586 send_response(sock, family, src_addr, addrlen,
587 result, qtype);
588 } else if (IS_ENABLED(CONFIG_MDNS_RESPONDER_DNS_SD)
589 && qtype == DNS_RR_TYPE_PTR) {
590 send_sd_response(sock, family, src_addr, addrlen,
591 &dns_msg, result);
592 }
593
594 } while (--queries);
595
596 ret = 0;
597
598 quit:
599 if (result) {
600 net_buf_unref(result);
601 }
602
603 return ret;
604 }
605
606 #if defined(CONFIG_NET_IPV6)
iface_ipv6_cb(struct net_if * iface,void * user_data)607 static void iface_ipv6_cb(struct net_if *iface, void *user_data)
608 {
609 struct in6_addr *addr = user_data;
610 int ret;
611
612 ret = net_ipv6_mld_join(iface, addr);
613 if (ret < 0) {
614 NET_DBG("Cannot join %s IPv6 multicast group (%d)",
615 net_sprint_ipv6_addr(addr), ret);
616 }
617 }
618
setup_ipv6_addr(struct sockaddr_in6 * local_addr)619 static void setup_ipv6_addr(struct sockaddr_in6 *local_addr)
620 {
621 create_ipv6_addr(local_addr);
622
623 net_if_foreach(iface_ipv6_cb, &local_addr->sin6_addr);
624 }
625 #endif /* CONFIG_NET_IPV6 */
626
627 #if defined(CONFIG_NET_IPV4)
iface_ipv4_cb(struct net_if * iface,void * user_data)628 static void iface_ipv4_cb(struct net_if *iface, void *user_data)
629 {
630 struct in_addr *addr = user_data;
631 int ret;
632
633 if (!net_if_is_up(iface)) {
634 struct net_if_mcast_addr *maddr;
635
636 NET_DBG("Interface %d is down, not joining mcast group yet",
637 net_if_get_by_iface(iface));
638
639 maddr = net_if_ipv4_maddr_add(iface, addr);
640 if (!maddr) {
641 NET_DBG("Cannot add multicast address %s",
642 net_sprint_ipv4_addr(addr));
643 }
644
645 return;
646 }
647
648 ret = net_ipv4_igmp_join(iface, addr, NULL);
649 if (ret < 0) {
650 NET_DBG("Cannot add IPv4 multicast address to iface %d",
651 net_if_get_by_iface(iface));
652 }
653 }
654
setup_ipv4_addr(struct sockaddr_in * local_addr)655 static void setup_ipv4_addr(struct sockaddr_in *local_addr)
656 {
657 create_ipv4_addr(local_addr);
658
659 net_if_foreach(iface_ipv4_cb, &local_addr->sin_addr);
660 }
661 #endif /* CONFIG_NET_IPV4 */
662
663 #if defined(CONFIG_NET_INTERFACE_NAME_LEN)
664 #define INTERFACE_NAME_LEN CONFIG_NET_INTERFACE_NAME_LEN
665 #else
666 #define INTERFACE_NAME_LEN 0
667 #endif
668
dispatcher_cb(void * my_ctx,int sock,struct sockaddr * addr,size_t addrlen,struct net_buf * dns_data,size_t len)669 static int dispatcher_cb(void *my_ctx, int sock,
670 struct sockaddr *addr, size_t addrlen,
671 struct net_buf *dns_data, size_t len)
672 {
673 int ret;
674
675 ARG_UNUSED(my_ctx);
676
677 ret = dns_read(sock, dns_data, len, addr, addrlen);
678 if (ret < 0 && ret != -EINVAL && ret != -ENOENT) {
679 NET_DBG("%s read failed (%d)", "mDNS", ret);
680 }
681
682 return ret;
683 }
684
register_dispatcher(struct mdns_responder_context * ctx,const struct net_socket_service_desc * svc,struct sockaddr * local,int ifindex,struct zsock_pollfd * fds,size_t fds_len)685 static int register_dispatcher(struct mdns_responder_context *ctx,
686 const struct net_socket_service_desc *svc,
687 struct sockaddr *local,
688 int ifindex,
689 struct zsock_pollfd *fds,
690 size_t fds_len)
691 {
692 ctx->dispatcher.type = DNS_SOCKET_RESPONDER;
693 ctx->dispatcher.cb = dispatcher_cb;
694 ctx->dispatcher.fds = fds;
695 ctx->dispatcher.fds_len = fds_len;
696 ctx->dispatcher.sock = ctx->sock;
697 ctx->dispatcher.svc = svc;
698 ctx->dispatcher.mdns_ctx = ctx;
699 ctx->dispatcher.pair = NULL;
700 ctx->dispatcher.ifindex = ifindex;
701
702 /* Mark the fd so that "net sockets" can show it. This is needed if there
703 * is already a socket bound to same port and the dispatcher will mux
704 * the connections. Without this, the FD in "net sockets" services list will
705 * show the socket descriptor value as -1.
706 */
707 svc->pev[0].event.fd = ctx->sock;
708
709 if (IS_ENABLED(CONFIG_NET_IPV6) && local->sa_family == AF_INET6) {
710 memcpy(&ctx->dispatcher.local_addr, local,
711 sizeof(struct sockaddr_in6));
712 } else if (IS_ENABLED(CONFIG_NET_IPV4) && local->sa_family == AF_INET) {
713 memcpy(&ctx->dispatcher.local_addr, local,
714 sizeof(struct sockaddr_in));
715 } else {
716 return -ENOTSUP;
717 }
718
719 return dns_dispatcher_register(&ctx->dispatcher);
720 }
721
init_listener(void)722 static int init_listener(void)
723 {
724 int ret, ok = 0, ifindex;
725 char name[INTERFACE_NAME_LEN + 1];
726 struct ifreq if_req;
727 struct net_if *iface;
728 int iface_count, fds_pos;
729
730 NET_IFACE_COUNT(&iface_count);
731 NET_DBG("Setting %s listener to %d interface%s", "mDNS", iface_count,
732 iface_count > 1 ? "s" : "");
733
734 #if defined(CONFIG_NET_IPV6)
735 /* Because there is only one IPv6 socket service context for all
736 * IPv6 sockets, we must collect the sockets in one place.
737 */
738 struct zsock_pollfd ipv6_fds[MAX_IPV6_IFACE_COUNT];
739 struct sockaddr_in6 local_addr6;
740 int v6;
741
742 if ((iface_count > MAX_IPV6_IFACE_COUNT && MAX_IPV6_IFACE_COUNT > 0)) {
743 NET_WARN("You have %d %s interfaces configured but there "
744 "are %d network interfaces in the system.",
745 MAX_IPV6_IFACE_COUNT, "IPv6", iface_count);
746 }
747
748 setup_ipv6_addr(&local_addr6);
749
750 ARRAY_FOR_EACH(ipv6_fds, i) {
751 ipv6_fds[i].fd = -1;
752 }
753
754 fds_pos = 0;
755
756 ARRAY_FOR_EACH(v6_ctx, i) {
757 ARRAY_FOR_EACH(v6_ctx[i].fds, j) {
758 v6_ctx[i].fds[j].fd = -1;
759 }
760
761 v6 = get_socket(AF_INET6);
762 if (v6 < 0) {
763 NET_ERR("Cannot get %s socket (%d %s interfaces). Max sockets is %d",
764 "IPv6", MAX_IPV6_IFACE_COUNT,
765 "IPv6", CONFIG_NET_MAX_CONTEXTS);
766 continue;
767 }
768
769 iface = net_if_get_by_index(i + 1);
770 if (iface == NULL) {
771 zsock_close(v6);
772 continue;
773 }
774
775 ifindex = net_if_get_by_iface(iface);
776
777 ret = net_if_get_name(iface, name, INTERFACE_NAME_LEN);
778 if (ret < 0) {
779 NET_DBG("Cannot get interface name for %d (%d)",
780 ifindex, ret);
781 } else {
782 memset(&if_req, 0, sizeof(if_req));
783 strncpy(if_req.ifr_name, name, sizeof(if_req.ifr_name) - 1);
784
785 ret = zsock_setsockopt(v6, SOL_SOCKET, SO_BINDTODEVICE,
786 &if_req, sizeof(if_req));
787 if (ret < 0) {
788 NET_DBG("Cannot bind sock %d to interface %d (%d)",
789 v6, ifindex, ret);
790 }
791 }
792
793 v6_ctx[i].sock = v6;
794 ret = -1;
795
796 ARRAY_FOR_EACH(v6_ctx[i].fds, j) {
797 if (v6_ctx[i].fds[j].fd == v6) {
798 ret = 0;
799 break;
800 }
801
802 if (v6_ctx[i].fds[j].fd < 0) {
803 v6_ctx[i].fds[j].fd = v6;
804 v6_ctx[i].fds[j].events = ZSOCK_POLLIN;
805 ipv6_fds[fds_pos].fd = v6;
806 ipv6_fds[fds_pos++].events = ZSOCK_POLLIN;
807 ret = 0;
808 break;
809 }
810 }
811
812 if (ret < 0) {
813 NET_DBG("Cannot set %s to socket (%d)", "polling", ret);
814 zsock_close(v6);
815 continue;
816 }
817
818 ret = register_dispatcher(&v6_ctx[i], &v6_svc, (struct sockaddr *)&local_addr6,
819 ifindex, ipv6_fds, ARRAY_SIZE(ipv6_fds));
820 if (ret < 0) {
821 NET_DBG("Cannot register %s %s socket service (%d)",
822 "IPv6", "mDNS", ret);
823 zsock_close(v6);
824 } else {
825 ok++;
826 }
827 }
828 #endif /* CONFIG_NET_IPV6 */
829
830 #if defined(CONFIG_NET_IPV4)
831 struct zsock_pollfd ipv4_fds[MAX_IPV4_IFACE_COUNT];
832 struct sockaddr_in local_addr4;
833 int v4;
834
835 if ((iface_count > MAX_IPV4_IFACE_COUNT && MAX_IPV4_IFACE_COUNT > 0)) {
836 NET_WARN("You have %d %s interfaces configured but there "
837 "are %d network interfaces in the system.",
838 MAX_IPV4_IFACE_COUNT, "IPv4", iface_count);
839 }
840
841 setup_ipv4_addr(&local_addr4);
842
843 ARRAY_FOR_EACH(ipv4_fds, i) {
844 ipv4_fds[i].fd = -1;
845 }
846
847 fds_pos = 0;
848
849 ARRAY_FOR_EACH(v4_ctx, i) {
850 ARRAY_FOR_EACH(v4_ctx[i].fds, j) {
851 v4_ctx[i].fds[j].fd = -1;
852 }
853
854 v4 = get_socket(AF_INET);
855 if (v4 < 0) {
856 NET_ERR("Cannot get %s socket (%d %s interfaces). Max sockets is %d",
857 "IPv4", MAX_IPV4_IFACE_COUNT,
858 "IPv4", CONFIG_NET_MAX_CONTEXTS);
859 continue;
860 }
861
862 iface = net_if_get_by_index(i + 1);
863 if (iface == NULL) {
864 zsock_close(v4);
865 continue;
866 }
867
868 ifindex = net_if_get_by_iface(iface);
869
870 ret = net_if_get_name(iface, name, INTERFACE_NAME_LEN);
871 if (ret < 0) {
872 NET_DBG("Cannot get interface name for %d (%d)",
873 ifindex, ret);
874 } else {
875 memset(&if_req, 0, sizeof(if_req));
876 strncpy(if_req.ifr_name, name, sizeof(if_req.ifr_name) - 1);
877
878 ret = zsock_setsockopt(v4, SOL_SOCKET, SO_BINDTODEVICE,
879 &if_req, sizeof(if_req));
880 if (ret < 0) {
881 NET_DBG("Cannot bind sock %d to interface %d (%d)",
882 v4, ifindex, ret);
883 }
884 }
885
886 v4_ctx[i].sock = v4;
887 ret = -1;
888
889 ARRAY_FOR_EACH(v4_ctx[i].fds, j) {
890 if (v4_ctx[i].fds[j].fd == v4) {
891 ret = 0;
892 break;
893 }
894
895 if (v4_ctx[i].fds[j].fd < 0) {
896 v4_ctx[i].fds[j].fd = v4;
897 v4_ctx[i].fds[j].events = ZSOCK_POLLIN;
898 ipv4_fds[fds_pos].fd = v4;
899 ipv4_fds[fds_pos++].events = ZSOCK_POLLIN;
900 ret = 0;
901 break;
902 }
903 }
904
905 if (ret < 0) {
906 NET_DBG("Cannot set %s to socket (%d)", "polling", ret);
907 zsock_close(v4);
908 continue;
909 }
910
911 ret = register_dispatcher(&v4_ctx[i], &v4_svc, (struct sockaddr *)&local_addr4,
912 ifindex, ipv4_fds, ARRAY_SIZE(ipv4_fds));
913 if (ret < 0) {
914 NET_DBG("Cannot register %s %s socket service (%d)",
915 "IPv4", "mDNS", ret);
916 zsock_close(v4);
917 } else {
918 ok++;
919 }
920 }
921 #endif /* CONFIG_NET_IPV4 */
922
923 if (!ok) {
924 NET_WARN("Cannot start %s responder", "mDNS");
925 }
926
927 return !ok;
928 }
929
mdns_responder_init(void)930 static int mdns_responder_init(void)
931 {
932 external_records = NULL;
933 external_records_count = 0;
934
935 net_mgmt_init_event_callback(&mgmt_cb, mdns_iface_event_handler,
936 NET_EVENT_IF_UP);
937
938 net_mgmt_add_event_callback(&mgmt_cb);
939
940 return init_listener();
941 }
942
mdns_responder_set_ext_records(const struct dns_sd_rec * records,size_t count)943 int mdns_responder_set_ext_records(const struct dns_sd_rec *records, size_t count)
944 {
945 if (records == NULL || count == 0) {
946 return -EINVAL;
947 }
948
949 external_records = records;
950 external_records_count = count;
951
952 return 0;
953 }
954
mdns_init_responder(void)955 void mdns_init_responder(void)
956 {
957 (void)mdns_responder_init();
958 }
959