1 /** @file
2 * @brief LLMNR responder
3 *
4 * This listens to LLMNR queries and responds to them.
5 */
6
7 /*
8 * Copyright (c) 2018 Intel Corporation
9 * Copyright (c) 2024 Nordic Semiconductor ASA
10 *
11 * SPDX-License-Identifier: Apache-2.0
12 */
13
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(net_llmnr_responder, CONFIG_LLMNR_RESPONDER_LOG_LEVEL);
16
17 #include <zephyr/kernel.h>
18 #include <zephyr/init.h>
19 #include <string.h>
20 #include <strings.h>
21 #include <errno.h>
22 #include <stdlib.h>
23
24 #include <zephyr/net/mld.h>
25 #include <zephyr/net/net_ip.h>
26 #include <zephyr/net/net_pkt.h>
27 #include <zephyr/net/dns_resolve.h>
28 #include <zephyr/net/socket_service.h>
29 #include <zephyr/net/udp.h>
30 #include <zephyr/net/igmp.h>
31
32 #include "dns_pack.h"
33 #include "ipv6.h"
34 #include "../../ip/net_stats.h"
35
36 #include "net_private.h"
37
38 #define LLMNR_LISTEN_PORT 5355
39
40 #define LLMNR_TTL CONFIG_LLMNR_RESPONDER_TTL /* In seconds */
41
42 #if defined(CONFIG_NET_IPV4)
43 static int ipv4;
44 static struct sockaddr_in local_addr4;
45 #endif
46
47 #if defined(CONFIG_NET_IPV6)
48 static int ipv6;
49 #endif
50
51 static struct net_mgmt_event_callback mgmt_cb;
52
53 #define BUF_ALLOC_TIMEOUT K_MSEC(100)
54
55 /* This value is recommended by RFC 1035 */
56 #define DNS_RESOLVER_MIN_BUF 2
57 #define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + \
58 CONFIG_LLMNR_RESOLVER_ADDITIONAL_BUF_CTR)
59
60 #if (IS_ENABLED(CONFIG_NET_IPV6) && IS_ENABLED(CONFIG_NET_IPV4))
61 #define LLMNR_MAX_POLL 2
62 #else
63 #define LLMNR_MAX_POLL 1
64 #endif
65
66 /* Socket polling for each server connection */
67 static struct zsock_pollfd fds[LLMNR_MAX_POLL];
68
69 static void svc_handler(struct net_socket_service_event *pev);
70 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc_llmnr, svc_handler, LLMNR_MAX_POLL);
71
72 NET_BUF_POOL_DEFINE(llmnr_msg_pool, DNS_RESOLVER_BUF_CTR,
73 DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL);
74
75 #if defined(CONFIG_NET_IPV6)
create_ipv6_addr(struct sockaddr_in6 * addr)76 static void create_ipv6_addr(struct sockaddr_in6 *addr)
77 {
78 addr->sin6_family = AF_INET6;
79 addr->sin6_port = htons(LLMNR_LISTEN_PORT);
80
81 /* Well known IPv6 ff02::1:3 address */
82 net_ipv6_addr_create(&addr->sin6_addr,
83 0xff02, 0, 0, 0, 0, 0, 0x01, 0x03);
84 }
85
create_ipv6_dst_addr(struct sockaddr_in6 * src_addr,struct sockaddr_in6 * addr)86 static void create_ipv6_dst_addr(struct sockaddr_in6 *src_addr,
87 struct sockaddr_in6 *addr)
88 {
89 addr->sin6_family = AF_INET6;
90 addr->sin6_port = src_addr->sin6_port;
91
92 net_ipv6_addr_copy_raw((uint8_t *)&addr->sin6_addr,
93 (uint8_t *)&src_addr->sin6_addr);
94 }
95 #endif
96
97 #if defined(CONFIG_NET_IPV4)
create_ipv4_addr(struct sockaddr_in * addr)98 static void create_ipv4_addr(struct sockaddr_in *addr)
99 {
100 addr->sin_family = AF_INET;
101 addr->sin_port = htons(LLMNR_LISTEN_PORT);
102
103 /* Well known IPv4 224.0.0.252 address */
104 addr->sin_addr.s_addr = htonl(0xE00000FC);
105 }
106
create_ipv4_dst_addr(struct sockaddr_in * src_addr,struct sockaddr_in * addr)107 static void create_ipv4_dst_addr(struct sockaddr_in *src_addr,
108 struct sockaddr_in *addr)
109 {
110 addr->sin_family = AF_INET;
111 addr->sin_port = src_addr->sin_port;
112
113 net_ipv4_addr_copy_raw((uint8_t *)&addr->sin_addr,
114 (uint8_t *)&src_addr->sin_addr);
115 }
116 #endif
117
llmnr_iface_event_handler(struct net_mgmt_event_callback * cb,uint64_t mgmt_event,struct net_if * iface)118 static void llmnr_iface_event_handler(struct net_mgmt_event_callback *cb,
119 uint64_t mgmt_event, struct net_if *iface)
120 {
121 if (mgmt_event == NET_EVENT_IF_UP) {
122 #if defined(CONFIG_NET_IPV4)
123 int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr, NULL);
124
125 if (ret < 0) {
126 NET_DBG("Cannot add IPv4 multicast address to iface %p",
127 iface);
128 }
129 #endif /* defined(CONFIG_NET_IPV4) */
130 }
131 }
132
get_socket(sa_family_t family)133 static int get_socket(sa_family_t family)
134 {
135 int ret;
136
137 ret = zsock_socket(family, SOCK_DGRAM, IPPROTO_UDP);
138 if (ret < 0) {
139 NET_DBG("Cannot get context (%d)", ret);
140 }
141
142 return ret;
143 }
144
bind_ctx(int sock,struct sockaddr * local_addr,socklen_t addrlen)145 static int bind_ctx(int sock,
146 struct sockaddr *local_addr,
147 socklen_t addrlen)
148 {
149 int ret;
150
151 if (sock < 0) {
152 return -EINVAL;
153 }
154
155 ret = zsock_bind(sock, local_addr, addrlen);
156 if (ret < 0) {
157 NET_DBG("Cannot bind to %s %s port (%d)", "LLMNR",
158 local_addr->sa_family == AF_INET ?
159 "IPv4" : "IPv6", ret);
160 return ret;
161 }
162
163 return ret;
164 }
165
setup_dns_hdr(uint8_t * buf,uint16_t answers,uint16_t dns_id)166 static void setup_dns_hdr(uint8_t *buf, uint16_t answers, uint16_t dns_id)
167 {
168 uint16_t offset;
169 uint16_t flags;
170
171 /* See RFC 1035, ch 4.1.1 and RFC 4795 ch 2.1.1 for header details */
172
173 flags = BIT(15); /* This is response */
174
175 UNALIGNED_PUT(htons(dns_id), (uint16_t *)(buf));
176 offset = DNS_HEADER_ID_LEN;
177
178 UNALIGNED_PUT(htons(flags), (uint16_t *)(buf+offset));
179 offset += DNS_HEADER_FLAGS_LEN;
180
181 UNALIGNED_PUT(htons(1), (uint16_t *)(buf + offset));
182 offset += DNS_QDCOUNT_LEN;
183
184 UNALIGNED_PUT(htons(answers), (uint16_t *)(buf + offset));
185 offset += DNS_ANCOUNT_LEN;
186
187 UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
188 offset += DNS_NSCOUNT_LEN;
189
190 UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
191 }
192
add_question(struct net_buf * query,enum dns_rr_type qtype)193 static void add_question(struct net_buf *query, enum dns_rr_type qtype)
194 {
195 char *dot = query->data + DNS_MSG_HEADER_SIZE;
196 char *prev = NULL;
197 uint16_t offset;
198
199 while ((dot = strchr(dot, '.'))) {
200 if (!prev) {
201 prev = dot++;
202 continue;
203 }
204
205 *prev = dot - prev - 1;
206 prev = dot++;
207 }
208
209 if (prev) {
210 *prev = strlen(prev) - 1;
211 }
212
213 offset = DNS_MSG_HEADER_SIZE + query->len + 1;
214 UNALIGNED_PUT(htons(qtype), (uint16_t *)(query->data+offset));
215
216 offset += DNS_QTYPE_LEN;
217 UNALIGNED_PUT(htons(DNS_CLASS_IN), (uint16_t *)(query->data+offset));
218 }
219
add_answer(struct net_buf * query,uint32_t ttl,uint16_t addr_len,const uint8_t * addr)220 static int add_answer(struct net_buf *query, uint32_t ttl,
221 uint16_t addr_len, const uint8_t *addr)
222 {
223 const uint16_t q_len = query->len + 1 + DNS_QTYPE_LEN + DNS_QCLASS_LEN;
224 uint16_t offset = DNS_MSG_HEADER_SIZE + q_len;
225
226 memcpy(query->data + offset, query->data + DNS_MSG_HEADER_SIZE, q_len);
227 offset += q_len;
228
229 UNALIGNED_PUT(htonl(ttl), query->data + offset);
230 offset += DNS_TTL_LEN;
231
232 UNALIGNED_PUT(htons(addr_len), query->data + offset);
233 offset += DNS_RDLENGTH_LEN;
234
235 memcpy(query->data + offset, addr, addr_len);
236
237 return offset + addr_len;
238 }
239
create_answer(enum dns_rr_type qtype,struct net_buf * query,uint16_t dns_id,uint16_t addr_len,const uint8_t * addr)240 static int create_answer(enum dns_rr_type qtype,
241 struct net_buf *query,
242 uint16_t dns_id,
243 uint16_t addr_len, const uint8_t *addr)
244 {
245 /* Prepare the response into the query buffer: move the name
246 * query buffer has to get enough free space: dns_hdr + query + answer
247 */
248 if ((net_buf_max_len(query) - query->len) < (DNS_MSG_HEADER_SIZE +
249 (DNS_QTYPE_LEN + DNS_QCLASS_LEN) * 2 +
250 DNS_TTL_LEN + DNS_RDLENGTH_LEN +
251 addr_len + query->len)) {
252 return -ENOBUFS;
253 }
254
255 memmove(query->data + DNS_MSG_HEADER_SIZE, query->data, query->len);
256
257 setup_dns_hdr(query->data, 1, dns_id);
258
259 add_question(query, qtype);
260
261 query->len = add_answer(query, LLMNR_TTL, addr_len, addr);
262
263 return 0;
264 }
265
266 #if defined(CONFIG_NET_IPV4)
get_ipv4_src(struct net_if * iface,struct in_addr * dst)267 static const uint8_t *get_ipv4_src(struct net_if *iface, struct in_addr *dst)
268 {
269 const struct in_addr *addr;
270
271 addr = net_if_ipv4_select_src_addr(iface, dst);
272 if (!addr || net_ipv4_is_addr_unspecified(addr)) {
273 return NULL;
274 }
275
276 return (const uint8_t *)addr;
277 }
278 #endif
279
280 #if defined(CONFIG_NET_IPV6)
get_ipv6_src(struct net_if * iface,struct in6_addr * dst)281 static const uint8_t *get_ipv6_src(struct net_if *iface, struct in6_addr *dst)
282 {
283 const struct in6_addr *addr;
284
285 addr = net_if_ipv6_select_src_addr(iface, dst);
286 if (!addr || net_ipv6_is_addr_unspecified(addr)) {
287 return NULL;
288 }
289
290 return (const uint8_t *)addr;
291 }
292 #endif
293
set_ttl_hop_limit(int sock,int level,int option,int new_limit)294 static int set_ttl_hop_limit(int sock, int level, int option, int new_limit)
295 {
296 return zsock_setsockopt(sock, level, option, &new_limit, sizeof(new_limit));
297 }
298
299 #if defined(CONFIG_NET_IPV4)
create_ipv4_answer(int sock,struct sockaddr_in * src_addr,enum dns_rr_type qtype,struct net_buf * query,uint16_t dns_id,struct sockaddr * dst,socklen_t * dst_len)300 static int create_ipv4_answer(int sock,
301 struct sockaddr_in *src_addr,
302 enum dns_rr_type qtype,
303 struct net_buf *query,
304 uint16_t dns_id,
305 struct sockaddr *dst,
306 socklen_t *dst_len)
307 {
308 const uint8_t *addr;
309 int addr_len;
310
311 create_ipv4_dst_addr(src_addr, net_sin(dst));
312
313 *dst_len = sizeof(struct sockaddr_in);
314
315 /* Select proper address according to destination */
316 addr = get_ipv4_src(NULL, &net_sin(dst)->sin_addr);
317 if (!addr) {
318 return -ENOENT;
319 }
320
321 addr_len = sizeof(struct in_addr);
322
323 if (create_answer(qtype, query, dns_id, addr_len, addr)) {
324 return -ENOMEM;
325 }
326
327 (void)set_ttl_hop_limit(sock, IPPROTO_IP, IP_MULTICAST_TTL, 255);
328
329 return 0;
330 }
331 #endif /* CONFIG_NET_IPV4 */
332
create_ipv6_answer(int sock,struct sockaddr_in6 * src_addr,enum dns_rr_type qtype,struct net_buf * query,uint16_t dns_id,struct sockaddr * dst,socklen_t * dst_len)333 static int create_ipv6_answer(int sock,
334 struct sockaddr_in6 *src_addr,
335 enum dns_rr_type qtype,
336 struct net_buf *query,
337 uint16_t dns_id,
338 struct sockaddr *dst,
339 socklen_t *dst_len)
340 {
341 #if defined(CONFIG_NET_IPV6)
342 const uint8_t *addr;
343 int addr_len;
344
345 create_ipv6_dst_addr(src_addr, net_sin6(dst));
346
347 *dst_len = sizeof(struct sockaddr_in6);
348
349 addr = get_ipv6_src(NULL, &src_addr->sin6_addr);
350 if (!addr) {
351 return -ENOENT;
352 }
353
354 addr_len = sizeof(struct in6_addr);
355
356 if (create_answer(qtype, query, dns_id, addr_len, addr)) {
357 return -ENOMEM;
358 }
359
360 (void)set_ttl_hop_limit(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255);
361
362 #endif /* CONFIG_NET_IPV6 */
363 return 0;
364 }
365
send_response(int sock,struct sockaddr * src_addr,size_t addrlen,struct net_buf * reply,enum dns_rr_type qtype,uint16_t dns_id)366 static int send_response(int sock,
367 struct sockaddr *src_addr,
368 size_t addrlen,
369 struct net_buf *reply,
370 enum dns_rr_type qtype,
371 uint16_t dns_id)
372 {
373 socklen_t dst_len;
374 int ret;
375 COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6),
376 (struct sockaddr_in6), (struct sockaddr_in)) dst;
377
378 if (IS_ENABLED(CONFIG_NET_IPV4) && src_addr->sa_family == AF_INET) {
379 ret = create_ipv4_answer(sock, (struct sockaddr_in *)src_addr,
380 qtype, reply, dns_id,
381 (struct sockaddr *)&dst, &dst_len);
382 if (ret < 0) {
383 return ret;
384 }
385 } else if (IS_ENABLED(CONFIG_NET_IPV6) && src_addr->sa_family == AF_INET6) {
386 ret = create_ipv6_answer(sock, (struct sockaddr_in6 *)src_addr,
387 qtype, reply, dns_id,
388 (struct sockaddr *)&dst, &dst_len);
389 if (ret < 0) {
390 return ret;
391 }
392 } else {
393 /* TODO: support also service PTRs */
394 return -EPFNOSUPPORT;
395 }
396
397 ret = zsock_sendto(sock, reply->data, reply->len, 0,
398 (struct sockaddr *)&dst, dst_len);
399 if (ret < 0) {
400 NET_DBG("Cannot send %s reply to %s (%d)", "LLMNR",
401 src_addr->sa_family == AF_INET ?
402 net_sprint_ipv4_addr(&net_sin((struct sockaddr *)&dst)->sin_addr) :
403 net_sprint_ipv6_addr(&net_sin6((struct sockaddr *)&dst)->sin6_addr),
404 ret);
405 } else {
406 struct net_if *iface = NULL;
407 struct sockaddr *addr = (struct sockaddr *)&dst;
408
409 if (IS_ENABLED(CONFIG_NET_IPV6) && src_addr->sa_family == AF_INET6) {
410 iface = net_if_ipv6_select_src_iface(&net_sin6(addr)->sin6_addr);
411 } else if (IS_ENABLED(CONFIG_NET_IPV4) && src_addr->sa_family == AF_INET) {
412 iface = net_if_ipv4_select_src_iface(&net_sin(addr)->sin_addr);
413 }
414
415 if (iface != NULL) {
416 net_stats_update_dns_sent(iface);
417 }
418 }
419
420 return ret;
421 }
422
dns_read(int sock,struct net_buf * dns_data,size_t len,struct sockaddr * src_addr,size_t addrlen,struct dns_addrinfo * info)423 static int dns_read(int sock,
424 struct net_buf *dns_data,
425 size_t len,
426 struct sockaddr *src_addr,
427 size_t addrlen,
428 struct dns_addrinfo *info)
429 {
430 /* Helper struct to track the dns msg received from the server */
431 const char *hostname = net_hostname_get();
432 int hostname_len = strlen(hostname);
433 struct net_buf *result;
434 struct dns_msg_t dns_msg;
435 uint16_t dns_id = 0U;
436 socklen_t optlen;
437 int data_len;
438 int queries;
439 int family;
440 int ret;
441
442 data_len = MIN(len, DNS_RESOLVER_MAX_BUF_SIZE);
443
444 /* Store the DNS query name into a temporary net_buf, which will be
445 * eventually used to send a response
446 */
447 result = net_buf_alloc(&llmnr_msg_pool, BUF_ALLOC_TIMEOUT);
448 if (!result) {
449 ret = -ENOMEM;
450 goto quit;
451 }
452
453 dns_msg.msg = dns_data->data;
454 dns_msg.msg_size = data_len;
455
456 ret = llmnr_unpack_query_header(&dns_msg, &dns_id);
457 if (ret < 0) {
458 ret = -EINVAL;
459 goto quit;
460 }
461
462 queries = ret;
463
464 optlen = sizeof(int);
465 (void)zsock_getsockopt(sock, SOL_SOCKET, SO_DOMAIN, &family, &optlen);
466
467 NET_DBG("Received %d %s from %s (id 0x%04x)", queries,
468 queries > 1 ? "queries" : "query",
469 family == AF_INET ?
470 net_sprint_ipv4_addr(&net_sin(src_addr)->sin_addr) :
471 net_sprint_ipv6_addr(&net_sin6(src_addr)->sin6_addr),
472 dns_id);
473
474 do {
475 enum dns_rr_type qtype;
476 enum dns_class qclass;
477
478 (void)memset(result->data, 0, net_buf_max_len(result));
479 result->len = 0U;
480
481 ret = dns_unpack_query(&dns_msg, result, &qtype, &qclass);
482 if (ret < 0) {
483 goto quit;
484 }
485
486 NET_DBG("[%d] query %s/%s label %s (%d bytes)", queries,
487 dns_qtype_to_str(qtype), "IN",
488 result->data, ret);
489
490 /* If the query matches to our hostname, then send reply */
491 if (!strncasecmp(hostname, result->data + 1, hostname_len) &&
492 (result->len - 1) >= hostname_len) {
493 NET_DBG("%s query to our hostname %s", "LLMNR",
494 hostname);
495 ret = send_response(sock, src_addr, addrlen, result, qtype,
496 dns_id);
497 if (ret < 0) {
498 NET_DBG("Cannot send response (%d)", ret);
499 }
500 }
501 } while (--queries);
502
503 ret = 0;
504
505 quit:
506 if (result) {
507 net_buf_unref(result);
508 }
509
510 return ret;
511 }
512
recv_data(struct net_socket_service_event * pev)513 static int recv_data(struct net_socket_service_event *pev)
514 {
515 COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6),
516 (struct sockaddr_in6), (struct sockaddr_in)) addr;
517 struct net_buf *dns_data = NULL;
518 struct dns_addrinfo info = { 0 };
519 size_t addrlen = sizeof(addr);
520 int ret, family = AF_UNSPEC, sock_error, len;
521 socklen_t optlen;
522
523 if ((pev->event.revents & ZSOCK_POLLERR) ||
524 (pev->event.revents & ZSOCK_POLLNVAL)) {
525 (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET,
526 SO_DOMAIN, &family, &optlen);
527 (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET,
528 SO_ERROR, &sock_error, &optlen);
529 NET_ERR("Receiver IPv%d socket error (%d)",
530 family == AF_INET ? 4 : 6, sock_error);
531 ret = DNS_EAI_SYSTEM;
532 goto quit;
533 }
534
535 dns_data = net_buf_alloc(&llmnr_msg_pool, BUF_ALLOC_TIMEOUT);
536 if (!dns_data) {
537 ret = -ENOENT;
538 goto quit;
539 }
540
541 ret = zsock_recvfrom(pev->event.fd, dns_data->data,
542 net_buf_max_len(dns_data), 0,
543 (struct sockaddr *)&addr, &addrlen);
544 if (ret < 0) {
545 ret = -errno;
546 NET_ERR("recv failed on IPv%d socket (%d)",
547 family == AF_INET ? 4 : 6, -ret);
548 goto free_buf;
549 }
550
551 len = ret;
552
553 ret = dns_read(pev->event.fd, dns_data, len,
554 (struct sockaddr *)&addr, addrlen, &info);
555 if (ret < 0 && ret != -EINVAL) {
556 NET_DBG("%s read failed (%d)", "LLMNR", ret);
557 }
558
559 free_buf:
560 net_buf_unref(dns_data);
561
562 quit:
563 return ret;
564 }
565
svc_handler(struct net_socket_service_event * pev)566 static void svc_handler(struct net_socket_service_event *pev)
567 {
568 int ret;
569
570 ret = recv_data(pev);
571 if (ret < 0) {
572 NET_ERR("DNS recv error (%d)", ret);
573 }
574 }
575
576 #if defined(CONFIG_NET_IPV6)
iface_ipv6_cb(struct net_if * iface,void * user_data)577 static void iface_ipv6_cb(struct net_if *iface, void *user_data)
578 {
579 struct in6_addr *addr = user_data;
580 int ret;
581
582 ret = net_ipv6_mld_join(iface, addr);
583 if (ret < 0) {
584 NET_DBG("Cannot join %s IPv6 multicast group to iface %d (%d)",
585 net_sprint_ipv6_addr(addr),
586 net_if_get_by_iface(iface),
587 ret);
588 }
589 }
590
setup_ipv6_addr(struct sockaddr_in6 * local_addr)591 static void setup_ipv6_addr(struct sockaddr_in6 *local_addr)
592 {
593 create_ipv6_addr(local_addr);
594
595 net_if_foreach(iface_ipv6_cb, &local_addr->sin6_addr);
596 }
597 #endif /* CONFIG_NET_IPV6 */
598
599 #if defined(CONFIG_NET_IPV4)
iface_ipv4_cb(struct net_if * iface,void * user_data)600 static void iface_ipv4_cb(struct net_if *iface, void *user_data)
601 {
602 struct in_addr *addr = user_data;
603 int ret;
604
605 ret = net_ipv4_igmp_join(iface, addr, NULL);
606 if (ret < 0) {
607 NET_DBG("Cannot add %s multicast address to iface %d", "IPv4",
608 net_if_get_by_iface(iface));
609 }
610 }
611
setup_ipv4_addr(struct sockaddr_in * local_addr)612 static void setup_ipv4_addr(struct sockaddr_in *local_addr)
613 {
614 create_ipv4_addr(local_addr);
615
616 net_if_foreach(iface_ipv4_cb, &local_addr->sin_addr);
617 }
618 #endif /* CONFIG_NET_IPV4 */
619
init_listener(void)620 static int init_listener(void)
621 {
622 int ret, ok = 0;
623
624 ARRAY_FOR_EACH(fds, j) {
625 fds[j].fd = -1;
626 }
627
628 #if defined(CONFIG_NET_IPV6)
629 {
630 static struct sockaddr_in6 local_addr;
631
632 setup_ipv6_addr(&local_addr);
633
634 ipv6 = get_socket(AF_INET6);
635
636 ret = bind_ctx(ipv6, (struct sockaddr *)&local_addr,
637 sizeof(local_addr));
638 if (ret < 0) {
639 zsock_close(ipv6);
640 goto ipv6_out;
641 }
642
643 ret = -ENOENT;
644
645 ARRAY_FOR_EACH(fds, j) {
646 if (fds[j].fd == ipv6) {
647 ret = 0;
648 break;
649 }
650
651 if (fds[j].fd < 0) {
652 fds[j].fd = ipv6;
653 fds[j].events = ZSOCK_POLLIN;
654 ret = 0;
655 break;
656 }
657 }
658
659 if (ret < 0) {
660 NET_DBG("Cannot set %s to socket (%d)", "polling", ret);
661 zsock_close(ipv6);
662 goto ipv6_out;
663 }
664
665 ret = net_socket_service_register(&svc_llmnr, fds, ARRAY_SIZE(fds), NULL);
666 if (ret < 0) {
667 NET_DBG("Cannot register %s %s socket service (%d)",
668 "IPv6", "LLMNR", ret);
669 zsock_close(ipv6);
670 } else {
671 ok++;
672 }
673 }
674 ipv6_out:
675 #endif /* CONFIG_NET_IPV6 */
676
677 #if defined(CONFIG_NET_IPV4)
678 {
679 setup_ipv4_addr(&local_addr4);
680
681 ipv4 = get_socket(AF_INET);
682
683 ret = bind_ctx(ipv4, (struct sockaddr *)&local_addr4,
684 sizeof(local_addr4));
685 if (ret < 0) {
686 zsock_close(ipv4);
687 goto ipv4_out;
688 }
689
690 ret = -ENOENT;
691
692 ARRAY_FOR_EACH(fds, j) {
693 if (fds[j].fd == ipv4) {
694 ret = 0;
695 break;
696 }
697
698 if (fds[j].fd < 0) {
699 fds[j].fd = ipv4;
700 fds[j].events = ZSOCK_POLLIN;
701 ret = 0;
702 break;
703 }
704 }
705
706 if (ret < 0) {
707 NET_DBG("Cannot set %s to socket (%d)", "polling", ret);
708 zsock_close(ipv4);
709 goto ipv4_out;
710 }
711
712 ret = net_socket_service_register(&svc_llmnr, fds, ARRAY_SIZE(fds), NULL);
713 if (ret < 0) {
714 NET_DBG("Cannot register %s %s socket service (%d)",
715 "IPv4", "LLMNR", ret);
716 zsock_close(ipv4);
717 } else {
718 ok++;
719 }
720 }
721 ipv4_out:
722 #endif /* CONFIG_NET_IPV4 */
723
724 if (!ok) {
725 NET_WARN("Cannot start %s responder", "LLMNR");
726 }
727
728 return !ok;
729 }
730
llmnr_responder_init(void)731 static int llmnr_responder_init(void)
732 {
733 net_mgmt_init_event_callback(&mgmt_cb, llmnr_iface_event_handler,
734 NET_EVENT_IF_UP);
735
736 net_mgmt_add_event_callback(&mgmt_cb);
737
738 return init_listener();
739 }
740
741 SYS_INIT(llmnr_responder_init, APPLICATION, CONFIG_LLMNR_RESPONDER_INIT_PRIO);
742