1 /**
2 * @file
3 * MDNS responder implementation
4 *
5 * @defgroup mdns MDNS
6 * @ingroup apps
7 *
8 * RFC 6762 - Multicast DNS<br>
9 * RFC 6763 - DNS-Based Service Discovery
10 *
11 * You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use MDNS!
12 *
13 * @verbinclude mdns.txt
14 *
15 * Things left to implement:
16 * -------------------------
17 *
18 * - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off...
19 * - Sending negative responses NSEC
20 * - Fragmenting replies if required
21 * - Individual known answer detection for all local IPv6 addresses
22 * - Dynamic size of outgoing packet
23 */
24
25 /*
26 * Copyright (c) 2015 Verisure Innovation AB
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without modification,
30 * are permitted provided that the following conditions are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright notice,
33 * this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright notice,
35 * this list of conditions and the following disclaimer in the documentation
36 * and/or other materials provided with the distribution.
37 * 3. The name of the author may not be used to endorse or promote products
38 * derived from this software without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
43 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
45 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
48 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
49 * OF SUCH DAMAGE.
50 *
51 * This file is part of the lwIP TCP/IP stack.
52 *
53 * Author: Erik Ekman <erik@kryo.se>
54 * Author: Jasper Verschueren <jasper.verschueren@apart-audio.com>
55 *
56 */
57
58 #include "lwip/apps/mdns.h"
59 #include "lwip/apps/mdns_priv.h"
60 #include "lwip/apps/mdns_domain.h"
61 #include "lwip/apps/mdns_out.h"
62 #include "lwip/netif.h"
63 #include "lwip/udp.h"
64 #include "lwip/ip_addr.h"
65 #include "lwip/mem.h"
66 #include "lwip/memp.h"
67 #include "lwip/prot/dns.h"
68 #include "lwip/prot/iana.h"
69 #include "lwip/timeouts.h"
70 #include "lwip/sys.h"
71
72 #include <string.h> /* memset */
73 #include <stdio.h> /* snprintf */
74
75 #if LWIP_MDNS_RESPONDER
76
77 #if (LWIP_IPV4 && !LWIP_IGMP)
78 #error "If you want to use MDNS with IPv4, you have to define LWIP_IGMP=1 in your lwipopts.h"
79 #endif
80 #if (LWIP_IPV6 && !LWIP_IPV6_MLD)
81 #error "If you want to use MDNS with IPv6, you have to define LWIP_IPV6_MLD=1 in your lwipopts.h"
82 #endif
83 #if (!LWIP_UDP)
84 #error "If you want to use MDNS, you have to define LWIP_UDP=1 in your lwipopts.h"
85 #endif
86 #ifndef LWIP_RAND
87 #error "If you want to use MDNS, you have to define LWIP_RAND=(random function) in your lwipopts.h"
88 #endif
89
90 #if LWIP_IPV4
91 #include "lwip/igmp.h"
92 /* IPv4 multicast group 224.0.0.251 */
93 static const ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT;
94 #endif
95
96 #if LWIP_IPV6
97 #include "lwip/mld6.h"
98 /* IPv6 multicast group FF02::FB */
99 static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT;
100 #endif
101
102 #define MDNS_IP_TTL 255
103
104 #if LWIP_MDNS_SEARCH
105 static struct mdns_request mdns_requests[MDNS_MAX_REQUESTS];
106 #endif
107
108 static u8_t mdns_netif_client_id;
109 static struct udp_pcb *mdns_pcb;
110 #if MDNS_RESP_USENETIF_EXTCALLBACK
NETIF_DECLARE_EXT_CALLBACK(netif_callback)111 NETIF_DECLARE_EXT_CALLBACK(netif_callback)
112 #endif
113 static mdns_name_result_cb_t mdns_name_result_cb;
114
115 #define NETIF_TO_HOST(netif) (struct mdns_host*)(netif_get_client_data(netif, mdns_netif_client_id))
116
117 /** Delayed response defines */
118 #define MDNS_RESPONSE_DELAY_MAX 120
119 #define MDNS_RESPONSE_DELAY_MIN 20
120 #define MDNS_RESPONSE_DELAY (LWIP_RAND() %(MDNS_RESPONSE_DELAY_MAX - \
121 MDNS_RESPONSE_DELAY_MIN) + MDNS_RESPONSE_DELAY_MIN)
122 /* Delayed response for truncated question defines */
123 #define MDNS_RESPONSE_TC_DELAY_MAX 500
124 #define MDNS_RESPONSE_TC_DELAY_MIN 400
125 #define MDNS_RESPONSE_TC_DELAY_MS (LWIP_RAND() % (MDNS_RESPONSE_TC_DELAY_MAX - \
126 MDNS_RESPONSE_TC_DELAY_MIN) + MDNS_RESPONSE_TC_DELAY_MIN)
127
128 /** Probing & announcing defines */
129 #define MDNS_PROBE_COUNT 3
130 #ifdef LWIP_RAND
131 /* first probe timeout SHOULD be random 0-250 ms*/
132 #define MDNS_INITIAL_PROBE_DELAY_MS (LWIP_RAND() % MDNS_PROBE_DELAY_MS)
133 #else
134 #define MDNS_INITIAL_PROBE_DELAY_MS MDNS_PROBE_DELAY_MS
135 #endif
136
137 #define MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS 1000
138 #define MDNS_PROBE_TIEBREAK_MAX_ANSWERS 5
139
140 #define MDNS_LEXICOGRAPHICAL_EQUAL 0
141 #define MDNS_LEXICOGRAPHICAL_EARLIER 1
142 #define MDNS_LEXICOGRAPHICAL_LATER 2
143
144 /* Delay between successive announcements (RFC6762 section 8.3)
145 * -> increase by a factor 2 with every response sent.
146 */
147 #define MDNS_ANNOUNCE_DELAY_MS 1000
148 /* Minimum 2 announces, may send up to 8 (RFC6762 section 8.3) */
149 #define MDNS_ANNOUNCE_COUNT 2
150
151 /** Information about received packet */
152 struct mdns_packet {
153 /** Sender IP/port */
154 ip_addr_t source_addr;
155 u16_t source_port;
156 /** If packet was received unicast */
157 u16_t recv_unicast;
158 /** Packet data */
159 struct pbuf *pbuf;
160 /** Current parsing offset in packet */
161 u16_t parse_offset;
162 /** Identifier. Used in legacy queries */
163 u16_t tx_id;
164 /** Number of questions in packet,
165 * read from packet header */
166 u16_t questions;
167 /** Number of unparsed questions */
168 u16_t questions_left;
169 /** Number of answers in packet */
170 u16_t answers;
171 /** Number of unparsed answers */
172 u16_t answers_left;
173 /** Number of authoritative answers in packet */
174 u16_t authoritative;
175 /** Number of unparsed authoritative answers */
176 u16_t authoritative_left;
177 /** Number of additional answers in packet */
178 u16_t additional;
179 /** Number of unparsed additional answers */
180 u16_t additional_left;
181 /** Chained list of known answer received after a truncated question */
182 struct mdns_packet *next_answer;
183 /** Chained list of truncated question that are waiting */
184 struct mdns_packet *next_tc_question;
185 };
186
187 /* list of received questions with TC flags set, waiting for known answers */
188 static struct mdns_packet *pending_tc_questions;
189
190 /* pool of received packets */
191 LWIP_MEMPOOL_DECLARE(MDNS_PKTS, MDNS_MAX_STORED_PKTS, sizeof (struct mdns_packet), "Stored mDNS packets")
192
193 struct mdns_question {
194 struct mdns_rr_info info;
195 /** unicast reply requested */
196 u16_t unicast;
197 };
198
199 struct mdns_answer_list {
200 u16_t offset[MDNS_PROBE_TIEBREAK_MAX_ANSWERS];
201 u16_t size;
202 };
203
204 static err_t mdns_parse_pkt_questions(struct netif *netif,
205 struct mdns_packet *pkt,
206 struct mdns_outmsg *reply);
207 static void mdns_define_probe_rrs_to_send(struct netif *netif,
208 struct mdns_outmsg *outmsg);
209 static void mdns_probe_and_announce(void* arg);
210 static void mdns_conflict_save_time(struct netif *netif);
211
212 /**
213 * Construction to make mdns struct accessible from mdns_out.c
214 * TODO:
215 * can we add the mdns struct to the netif like we do for dhcp, autoip,...?
216 * Then this is not needed any more.
217 *
218 * @param netif The network interface
219 * @return mdns struct
220 */
221 struct mdns_host*
netif_mdns_data(struct netif * netif)222 netif_mdns_data(struct netif *netif) {
223 return NETIF_TO_HOST(netif);
224 }
225
226 /**
227 * Construction to access the mdns udp pcb.
228 *
229 * @return udp_pcb struct of mdns
230 */
231 struct udp_pcb*
get_mdns_pcb(void)232 get_mdns_pcb(void)
233 {
234 return mdns_pcb;
235 }
236
237 /**
238 * Check which replies we should send for a host/netif based on question
239 * @param netif The network interface that received the question
240 * @param rr Domain/type/class from a question
241 * @param reverse_v6_reply Bitmask of which IPv6 addresses to send reverse PTRs for
242 * if reply bit has REPLY_HOST_PTR_V6 set
243 * @return Bitmask of which replies to send
244 */
245 static int
check_host(struct netif * netif,struct mdns_rr_info * rr,u8_t * reverse_v6_reply)246 check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply)
247 {
248 err_t res;
249 int replies = 0;
250 struct mdns_domain mydomain;
251
252 LWIP_UNUSED_ARG(reverse_v6_reply); /* if ipv6 is disabled */
253
254 if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) {
255 /* Invalid class */
256 return replies;
257 }
258
259 /* Handle PTR for our addresses */
260 if (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY) {
261 #if LWIP_IPV6
262 int i;
263 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
264 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
265 res = mdns_build_reverse_v6_domain(&mydomain, netif_ip6_addr(netif, i));
266 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
267 replies |= REPLY_HOST_PTR_V6;
268 /* Mark which addresses where requested */
269 if (reverse_v6_reply) {
270 *reverse_v6_reply |= (1 << i);
271 }
272 }
273 }
274 }
275 #endif
276 #if LWIP_IPV4
277 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
278 res = mdns_build_reverse_v4_domain(&mydomain, netif_ip4_addr(netif));
279 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
280 replies |= REPLY_HOST_PTR_V4;
281 }
282 }
283 #endif
284 }
285
286 res = mdns_build_host_domain(&mydomain, NETIF_TO_HOST(netif));
287 /* Handle requests for our hostname */
288 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
289 /* TODO return NSEC if unsupported protocol requested */
290 #if LWIP_IPV4
291 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))
292 && (rr->type == DNS_RRTYPE_A || rr->type == DNS_RRTYPE_ANY)) {
293 replies |= REPLY_HOST_A;
294 }
295 #endif
296 #if LWIP_IPV6
297 if (rr->type == DNS_RRTYPE_AAAA || rr->type == DNS_RRTYPE_ANY) {
298 replies |= REPLY_HOST_AAAA;
299 }
300 #endif
301 }
302
303 return replies;
304 }
305
306 /**
307 * Check which replies we should send for a service based on question
308 * @param service A registered MDNS service
309 * @param rr Domain/type/class from a question
310 * @return Bitmask of which replies to send
311 */
312 static int
check_service(struct mdns_service * service,struct mdns_rr_info * rr)313 check_service(struct mdns_service *service, struct mdns_rr_info *rr)
314 {
315 err_t res;
316 int replies = 0;
317 struct mdns_domain mydomain;
318
319 if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) {
320 /* Invalid class */
321 return 0;
322 }
323
324 res = mdns_build_dnssd_domain(&mydomain);
325 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) &&
326 (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) {
327 /* Request for all service types */
328 replies |= REPLY_SERVICE_TYPE_PTR;
329 }
330
331 res = mdns_build_service_domain(&mydomain, service, 0);
332 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) &&
333 (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) {
334 /* Request for the instance of my service */
335 replies |= REPLY_SERVICE_NAME_PTR;
336 }
337
338 res = mdns_build_service_domain(&mydomain, service, 1);
339 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
340 /* Request for info about my service */
341 if (rr->type == DNS_RRTYPE_SRV || rr->type == DNS_RRTYPE_ANY) {
342 replies |= REPLY_SERVICE_SRV;
343 }
344 if (rr->type == DNS_RRTYPE_TXT || rr->type == DNS_RRTYPE_ANY) {
345 replies |= REPLY_SERVICE_TXT;
346 }
347 }
348
349 return replies;
350 }
351
352 #if LWIP_MDNS_SEARCH
353 /**
354 * Check if question belong to a specified request
355 * @param request A ongoing MDNS request
356 * @param rr Domain/type/class from an answer
357 * @return Bitmask of which matching replies
358 */
359 static int
check_request(struct mdns_request * request,struct mdns_rr_info * rr)360 check_request(struct mdns_request *request, struct mdns_rr_info *rr)
361 {
362 err_t res;
363 int replies = 0;
364 struct mdns_domain mydomain;
365
366 if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) {
367 /* Invalid class */
368 return 0;
369 }
370
371 res = mdns_build_request_domain(&mydomain, request, 0);
372 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) &&
373 (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) {
374 /* Request for the instance of my service */
375 replies |= REPLY_SERVICE_TYPE_PTR;
376 }
377 res = mdns_build_request_domain(&mydomain, request, 1);
378 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
379 /* Request for info about my service */
380 if (rr->type == DNS_RRTYPE_SRV || rr->type == DNS_RRTYPE_ANY) {
381 replies |= REPLY_SERVICE_SRV;
382 }
383 if (rr->type == DNS_RRTYPE_TXT || rr->type == DNS_RRTYPE_ANY) {
384 replies |= REPLY_SERVICE_TXT;
385 }
386 }
387 return replies;
388 }
389 #endif
390
391 /**
392 * Helper function for mdns_read_question/mdns_read_answer
393 * Reads a domain, type and class from the packet
394 * @param pkt The MDNS packet to read from. The parse_offset field will be
395 * incremented to point to the next unparsed byte.
396 * @param info The struct to fill with domain, type and class
397 * @return ERR_OK on success, an err_t otherwise
398 */
399 static err_t
mdns_read_rr_info(struct mdns_packet * pkt,struct mdns_rr_info * info)400 mdns_read_rr_info(struct mdns_packet *pkt, struct mdns_rr_info *info)
401 {
402 u16_t field16, copied;
403 pkt->parse_offset = mdns_readname(pkt->pbuf, pkt->parse_offset, &info->domain);
404 if (pkt->parse_offset == MDNS_READNAME_ERROR) {
405 return ERR_VAL;
406 }
407
408 copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset);
409 if (copied != sizeof(field16)) {
410 return ERR_VAL;
411 }
412 pkt->parse_offset += copied;
413 info->type = lwip_ntohs(field16);
414
415 copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset);
416 if (copied != sizeof(field16)) {
417 return ERR_VAL;
418 }
419 pkt->parse_offset += copied;
420 info->klass = lwip_ntohs(field16);
421
422 return ERR_OK;
423 }
424
425 /**
426 * Read a question from the packet.
427 * All questions have to be read before the answers.
428 * @param pkt The MDNS packet to read from. The questions_left field will be decremented
429 * and the parse_offset will be updated.
430 * @param question The struct to fill with question data
431 * @return ERR_OK on success, an err_t otherwise
432 */
433 static err_t
mdns_read_question(struct mdns_packet * pkt,struct mdns_question * question)434 mdns_read_question(struct mdns_packet *pkt, struct mdns_question *question)
435 {
436 /* Safety check */
437 if (pkt->pbuf->tot_len < pkt->parse_offset) {
438 return ERR_VAL;
439 }
440
441 if (pkt->questions_left) {
442 err_t res;
443 pkt->questions_left--;
444
445 memset(question, 0, sizeof(struct mdns_question));
446 res = mdns_read_rr_info(pkt, &question->info);
447 if (res != ERR_OK) {
448 return res;
449 }
450
451 /* Extract unicast flag from class field */
452 question->unicast = question->info.klass & 0x8000;
453 question->info.klass &= 0x7FFF;
454
455 return ERR_OK;
456 }
457 return ERR_VAL;
458 }
459
460 /**
461 * Read an answer from the packet
462 * The variable length reply is not copied, its pbuf offset and length is stored instead.
463 * @param pkt The MDNS packet to read. The num_left field will be decremented and
464 * the parse_offset will be updated.
465 * @param answer The struct to fill with answer data
466 * @param num_left number of answers left -> answers, authoritative or additional
467 * @return ERR_OK on success, an err_t otherwise
468 */
469 static err_t
mdns_read_answer(struct mdns_packet * pkt,struct mdns_answer * answer,u16_t * num_left)470 mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer, u16_t *num_left)
471 {
472 /* Read questions first */
473 if (pkt->questions_left) {
474 return ERR_VAL;
475 }
476
477 /* Safety check */
478 if (pkt->pbuf->tot_len < pkt->parse_offset) {
479 return ERR_VAL;
480 }
481
482 if (*num_left) {
483 u16_t copied, field16;
484 u32_t ttl;
485 err_t res;
486 (*num_left)--;
487
488 memset(answer, 0, sizeof(struct mdns_answer));
489 res = mdns_read_rr_info(pkt, &answer->info);
490 if (res != ERR_OK) {
491 return res;
492 }
493
494 /* Extract cache_flush flag from class field */
495 answer->cache_flush = answer->info.klass & 0x8000;
496 answer->info.klass &= 0x7FFF;
497
498 copied = pbuf_copy_partial(pkt->pbuf, &ttl, sizeof(ttl), pkt->parse_offset);
499 if (copied != sizeof(ttl)) {
500 return ERR_VAL;
501 }
502 pkt->parse_offset += copied;
503 answer->ttl = lwip_ntohl(ttl);
504
505 copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset);
506 if (copied != sizeof(field16)) {
507 return ERR_VAL;
508 }
509 pkt->parse_offset += copied;
510 answer->rd_length = lwip_ntohs(field16);
511
512 answer->rd_offset = pkt->parse_offset;
513 pkt->parse_offset += answer->rd_length;
514
515 return ERR_OK;
516 }
517 return ERR_VAL;
518 }
519
520 /**
521 * Send unsolicited answer containing all our known data
522 * @param netif The network interface to send on
523 * @param destination The target address to send to (usually multicast address)
524 */
525 static void
mdns_announce(struct netif * netif,const ip_addr_t * destination)526 mdns_announce(struct netif *netif, const ip_addr_t *destination)
527 {
528 struct mdns_outmsg announce;
529 int i;
530 struct mdns_host *mdns = NETIF_TO_HOST(netif);
531
532 memset(&announce, 0, sizeof(announce));
533 announce.cache_flush = 1;
534 #if LWIP_IPV4
535 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
536 announce.host_replies = REPLY_HOST_A | REPLY_HOST_PTR_V4;
537 }
538 #endif
539 #if LWIP_IPV6
540 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
541 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
542 announce.host_replies |= REPLY_HOST_AAAA | REPLY_HOST_PTR_V6;
543 announce.host_reverse_v6_replies |= (1 << i);
544 }
545 }
546 #endif
547
548 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
549 struct mdns_service *serv = mdns->services[i];
550 if (serv) {
551 announce.serv_replies[i] = REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR |
552 REPLY_SERVICE_SRV | REPLY_SERVICE_TXT;
553 }
554 }
555
556 announce.dest_port = LWIP_IANA_PORT_MDNS;
557 SMEMCPY(&announce.dest_addr, destination, sizeof(announce.dest_addr));
558 announce.flags = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE;
559 mdns_send_outpacket(&announce, netif);
560 }
561
562 /**
563 * Perform lexicographical comparison to define the lexicographical order of the
564 * records.
565 *
566 * @param pkt_a first packet (needed for rr data)
567 * @param pkt_b second packet (needed for rr data)
568 * @param ans_a first rr
569 * @param ans_b second rr
570 * @param result pointer to save result in -> MDNS_LEXICOGRAPHICAL_EQUAL,
571 * MDNS_LEXICOGRAPHICAL_LATER or MDNS_LEXICOGRAPHICAL_EARLIER.
572 * @return err_t ERR_OK if result is good, ERR_VAL if domain decompression failed.
573 */
574 static err_t
mdns_lexicographical_comparison(struct mdns_packet * pkt_a,struct mdns_packet * pkt_b,struct mdns_answer * ans_a,struct mdns_answer * ans_b,u8_t * result)575 mdns_lexicographical_comparison(struct mdns_packet *pkt_a, struct mdns_packet *pkt_b,
576 struct mdns_answer *ans_a, struct mdns_answer *ans_b,
577 u8_t *result)
578 {
579 int len, i;
580 u8_t a_rd, b_rd;
581 u16_t res;
582 struct mdns_domain domain_a, domain_b;
583
584 /* Compare classes */
585 if (ans_a->info.klass != ans_b->info.klass) {
586 if (ans_a->info.klass > ans_b->info.klass) {
587 *result = MDNS_LEXICOGRAPHICAL_LATER;
588 return ERR_OK;
589 }
590 else {
591 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
592 return ERR_OK;
593 }
594 }
595 /* Compare types */
596 if (ans_a->info.type != ans_b->info.type) {
597 if (ans_a->info.type > ans_b->info.type) {
598 *result = MDNS_LEXICOGRAPHICAL_LATER;
599 return ERR_OK;
600 }
601 else {
602 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
603 return ERR_OK;
604 }
605 }
606
607 /* Compare rr data section
608 * Name compression:
609 * We have 4 different RR types in our authoritative section (if IPv4 and IPv6 is enabled): A,
610 * AAAA, SRV and TXT. Only one of the 4 can be subject to name compression in the rdata, the SRV
611 * record. As stated in the RFC6762 section 8.2: the names must be uncompressed before comparison.
612 * We only need to take the SRV record into account. It's the only one that in a comparison with
613 * compressed data could lead to rdata comparison. Others will already stop after the type
614 * comparison. So if we get passed the class and type comparison we need to check if the
615 * comparison contains an SRV record. If so, we need a different comparison method.
616 */
617
618 /* The answers do not contain an SRV record */
619 if (ans_a->info.type != DNS_RRTYPE_SRV && ans_b->info.type != DNS_RRTYPE_SRV) {
620 len = LWIP_MIN(ans_a->rd_length, ans_b->rd_length);
621 for (i = 0; i < len; i++) {
622 a_rd = pbuf_get_at(pkt_a->pbuf, (u16_t)(ans_a->rd_offset + i));
623 b_rd = pbuf_get_at(pkt_b->pbuf, (u16_t)(ans_b->rd_offset + i));
624 if (a_rd != b_rd) {
625 if (a_rd > b_rd) {
626 *result = MDNS_LEXICOGRAPHICAL_LATER;
627 return ERR_OK;
628 }
629 else {
630 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
631 return ERR_OK;
632 }
633 }
634 }
635 /* If the overlapping data is the same, compare the length */
636 if (ans_a->rd_length != ans_b->rd_length) {
637 if (ans_a->rd_length > ans_b->rd_length) {
638 *result = MDNS_LEXICOGRAPHICAL_LATER;
639 return ERR_OK;
640 }
641 else {
642 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
643 return ERR_OK;
644 }
645 }
646 }
647 /* Because the types are guaranteed equal here, we know they are both SRV RRs */
648 else {
649 /* We will first compare the priority, weight and port */
650 for (i = 0; i < 6; i++) {
651 a_rd = pbuf_get_at(pkt_a->pbuf, (u16_t)(ans_a->rd_offset + i));
652 b_rd = pbuf_get_at(pkt_b->pbuf, (u16_t)(ans_b->rd_offset + i));
653 if (a_rd != b_rd) {
654 if (a_rd > b_rd) {
655 *result = MDNS_LEXICOGRAPHICAL_LATER;
656 return ERR_OK;
657 }
658 else {
659 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
660 return ERR_OK;
661 }
662 }
663 }
664 /* Decompress names if compressed and save in domain_a or domain_b */
665 res = mdns_readname(pkt_a->pbuf, ans_a->rd_offset + 6, &domain_a);
666 if (res == MDNS_READNAME_ERROR) {
667 return ERR_VAL;
668 }
669 res = mdns_readname(pkt_b->pbuf, ans_b->rd_offset + 6, &domain_b);
670 if (res == MDNS_READNAME_ERROR) {
671 return ERR_VAL;
672 }
673 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: domain a: len = %d, name = ", domain_a.name[0]));
674 mdns_domain_debug_print(&domain_a);
675 LWIP_DEBUGF(MDNS_DEBUG, ("\n"));
676 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: domain b: len = %d, name = ", domain_b.name[0]));
677 mdns_domain_debug_print(&domain_b);
678 LWIP_DEBUGF(MDNS_DEBUG, ("\n"));
679 /* Compare names pairwise */
680 len = LWIP_MIN(domain_a.length, domain_b.length);
681 for (i = 0; i < len; i++) {
682 if (domain_a.name[i] != domain_b.name[i]) {
683 if (domain_a.name[i] > domain_b.name[i]) {
684 *result = MDNS_LEXICOGRAPHICAL_LATER;
685 return ERR_OK;
686 }
687 else {
688 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
689 return ERR_OK;
690 }
691 }
692 }
693 /* If the overlapping data is the same, compare the length */
694 if (domain_a.length != domain_b.length) {
695 if (domain_a.length > domain_b.length) {
696 *result = MDNS_LEXICOGRAPHICAL_LATER;
697 return ERR_OK;
698 }
699 else {
700 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
701 return ERR_OK;
702 }
703 }
704 }
705 /* They are exactly the same */
706 *result = MDNS_LEXICOGRAPHICAL_EQUAL;
707 return ERR_OK;
708 }
709
710 /**
711 * Clear authoritative answer list
712 *
713 * @param a_list answer list to clear
714 */
715 static void
mdns_init_answer_list(struct mdns_answer_list * a_list)716 mdns_init_answer_list(struct mdns_answer_list *a_list)
717 {
718 int i;
719 a_list->size = 0;
720 for(i = 0; i < MDNS_PROBE_TIEBREAK_MAX_ANSWERS; i++) {
721 a_list->offset[i] = 0;
722 }
723 }
724
725 /**
726 * Pushes the offset of the answer on a lexicographically later sorted list.
727 * We use a simple insertion sort because most of the time we are only sorting
728 * two items. The answers are sorted from the smallest to the largest.
729 *
730 * @param a_list Answer list to which to add the answer
731 * @param pkt Packet where answer originated
732 * @param new_offset Offset of the new answer in the packet
733 * @param new_answer The new answer
734 * @return err_t ERR_MEM if list is full
735 */
736 static err_t
mdns_push_answer_to_sorted_list(struct mdns_answer_list * a_list,struct mdns_packet * pkt,u16_t new_offset,struct mdns_answer * new_answer)737 mdns_push_answer_to_sorted_list(struct mdns_answer_list *a_list,
738 struct mdns_packet *pkt,
739 u16_t new_offset,
740 struct mdns_answer *new_answer)
741 {
742 int i;
743 struct mdns_answer a;
744 int pos = a_list->size;
745 err_t res = ERR_OK;
746 u8_t result;
747 u16_t num_left = pkt->authoritative;
748 u16_t parse_offset = pkt->parse_offset;
749
750 /* Check size */
751 if ((a_list->size + 1) >= MDNS_PROBE_TIEBREAK_MAX_ANSWERS) {
752 return ERR_MEM;
753 }
754 /* Search location and open a location */
755 for (i = 0; i < a_list->size; i++) {
756 /* Read answers already in the list from pkt */
757 pkt->parse_offset = a_list->offset[i];
758 res = mdns_read_answer(pkt, &a, &num_left);
759 if (res != ERR_OK) {
760 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
761 return res;
762 }
763 /* Compare them with the new answer to find it's place */
764 res = mdns_lexicographical_comparison(pkt, pkt, &a, new_answer, &result);
765 if (res != ERR_OK) {
766 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to compare answers, skipping probe packet\n"));
767 return res;
768 }
769 if (result == MDNS_LEXICOGRAPHICAL_LATER) {
770 int j;
771 pos = i;
772 for (j = (a_list->size + 1); j>i; j--) {
773 a_list->offset[j] = a_list->offset[j-1];
774 }
775 break;
776 }
777 }
778 /* Insert new value */
779 a_list->offset[pos] = new_offset;
780 a_list->size++;
781 /* Reset parse offset for further evaluation */
782 pkt->parse_offset = parse_offset;
783 return res;
784 }
785
786 /**
787 * Check if the given answer answers the give question
788 *
789 * @param q query to find answer for
790 * @param a answer to given query
791 * @return 1 it a answers q, 0 if not
792 */
793 static u8_t
mdns_is_answer_to_question(struct mdns_question * q,struct mdns_answer * a)794 mdns_is_answer_to_question(struct mdns_question *q, struct mdns_answer *a)
795 {
796 if (q->info.type == DNS_RRTYPE_ANY || q->info.type == a->info.type) {
797 /* The types match or question type is any */
798 if (mdns_domain_eq(&q->info.domain, &a->info.domain)) {
799 return 1;
800 }
801 }
802 return 0;
803 }
804
805 /**
806 * Converts the output packet to the input packet format for probe tiebreaking
807 *
808 * @param inpkt destination packet for conversion
809 * @param outpkt source packet for conversion
810 */
811 static void
mdns_convert_out_to_in_pkt(struct mdns_packet * inpkt,struct mdns_outpacket * outpkt)812 mdns_convert_out_to_in_pkt(struct mdns_packet *inpkt, struct mdns_outpacket *outpkt)
813 {
814 inpkt->pbuf = outpkt->pbuf;
815 inpkt->parse_offset = SIZEOF_DNS_HDR;
816
817 inpkt->questions = inpkt->questions_left = outpkt->questions;
818 inpkt->answers = inpkt->answers_left = outpkt->answers;
819 inpkt->authoritative = inpkt->authoritative_left = outpkt->authoritative;
820 inpkt->additional = inpkt->additional_left = outpkt->additional;
821 }
822
823 /**
824 * Debug print to print the answer part that is lexicographically compared
825 *
826 * @param pkt Packet where answer originated
827 * @param a The answer to print
828 */
829 static void
mdns_debug_print_answer(struct mdns_packet * pkt,struct mdns_answer * a)830 mdns_debug_print_answer(struct mdns_packet *pkt, struct mdns_answer *a)
831 {
832 #ifdef LWIP_DEBUG
833 /* Arbitrarily chose 200 -> don't want to see more then that. It's only
834 * for debug so not that important. */
835 char string[200];
836 int i;
837 int pos;
838
839 pos = snprintf(string, sizeof(string), "Type = %2d, class = %1d, rdata = ", a->info.type, a->info.klass);
840 for (i = 0; ((i < a->rd_length) && ((pos + 4*i) < 195)) ; i++) {
841 snprintf(&string[pos + 4*i], 5, "%3d ", (u8_t)pbuf_get_at(pkt->pbuf, (u16_t)(a->rd_offset + i)));
842 }
843 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: %s\n", string));
844 #else
845 LWIP_UNUSED_ARG(pkt);
846 LWIP_UNUSED_ARG(a);
847 #endif
848 }
849
850 /**
851 * Perform probe tiebreaking according to RFC6762 section 8.2
852 *
853 * @param netif network interface of incoming packet
854 * @param pkt incoming packet
855 */
856 static void
mdns_handle_probe_tiebreaking(struct netif * netif,struct mdns_packet * pkt)857 mdns_handle_probe_tiebreaking(struct netif *netif, struct mdns_packet *pkt)
858 {
859 struct mdns_question pkt_q, my_q, q_dummy;
860 struct mdns_answer pkt_a, my_a;
861 struct mdns_outmsg myprobe_msg;
862 struct mdns_outpacket myprobe_outpkt;
863 struct mdns_packet myprobe_inpkt;
864 struct mdns_answer_list pkt_a_list, my_a_list;
865 u16_t save_parse_offset;
866 u16_t pkt_parse_offset, myprobe_parse_offset, myprobe_questions_left;
867 err_t res;
868 u8_t match, result;
869 int min, i;
870
871 /* Generate probe packet to perform comparison.
872 * This is a lot of calculation at this stage without any pre calculation
873 * needed. It should be evaluated if this is the best approach.
874 */
875 mdns_define_probe_rrs_to_send(netif, &myprobe_msg);
876 memset(&myprobe_outpkt, 0, sizeof(myprobe_outpkt));
877 memset(&myprobe_inpkt, 0, sizeof(myprobe_inpkt));
878 res = mdns_create_outpacket(netif, &myprobe_msg, &myprobe_outpkt);
879 if (res != ERR_OK) {
880 goto cleanup;
881 }
882 mdns_convert_out_to_in_pkt(&myprobe_inpkt, &myprobe_outpkt);
883
884 /* Loop over all our probes to search for matches */
885 while (myprobe_inpkt.questions_left) {
886 /* Read one of our probe questions to check if pkt contains same question */
887 res = mdns_read_question(&myprobe_inpkt, &my_q);
888 if (res != ERR_OK) {
889 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
890 goto cleanup;
891 }
892 /* Remember parse offsets so we can restart the search for the next question */
893 pkt_parse_offset = pkt->parse_offset;
894 myprobe_parse_offset = myprobe_inpkt.parse_offset;
895 /* Remember questions left of our probe packet */
896 myprobe_questions_left = myprobe_inpkt.questions_left;
897 /* Reset match flag */
898 match = 0;
899 /* Search for a matching probe in the incoming packet */
900 while (pkt->questions_left) {
901 /* Read probe questions one by one */
902 res = mdns_read_question(pkt, &pkt_q);
903 if (res != ERR_OK) {
904 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
905 goto cleanup;
906 }
907 /* Stop evaluating if the class is not supported */
908 if (pkt_q.info.klass != DNS_RRCLASS_IN && pkt_q.info.klass != DNS_RRCLASS_ANY) {
909 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: question class not supported, skipping probe packet\n"));
910 goto cleanup;
911 }
912 /* We probe for type any, so we do not have to compare types */
913 /* Compare if we are probing for the same domain */
914 if (mdns_domain_eq(&pkt_q.info.domain, &my_q.info.domain)) {
915 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: We are probing for the same rr\n"));
916 match = 1;
917 break;
918 }
919 }
920 /* When matched start evaluating the authoritative section */
921 if (match) {
922 /* Ignore all following questions to be able to get to the authoritative answers */
923 while (pkt->questions_left) {
924 res = mdns_read_question(pkt, &q_dummy);
925 if (res != ERR_OK) {
926 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
927 goto cleanup;
928 }
929 }
930 while (myprobe_inpkt.questions_left) {
931 res = mdns_read_question(&myprobe_inpkt, &q_dummy);
932 if (res != ERR_OK) {
933 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
934 goto cleanup;
935 }
936 }
937
938 /* Extract and sort our authoritative answers that answer our question */
939 mdns_init_answer_list(&my_a_list);
940 while(myprobe_inpkt.authoritative_left) {
941 save_parse_offset = myprobe_inpkt.parse_offset;
942 res = mdns_read_answer(&myprobe_inpkt, &my_a, &myprobe_inpkt.authoritative_left);
943 if (res != ERR_OK) {
944 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
945 goto cleanup;
946 }
947 if (mdns_is_answer_to_question(&my_q, &my_a)) {
948 /* Add to list */
949 res = mdns_push_answer_to_sorted_list(&my_a_list, &myprobe_inpkt, save_parse_offset, &my_a);
950 if (res != ERR_OK) {
951 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to add answer, skipping probe packet\n"));
952 goto cleanup;
953 }
954 }
955 }
956 /* Extract and sort the packets authoritative answers that answer the
957 question */
958 mdns_init_answer_list(&pkt_a_list);
959 while(pkt->authoritative_left) {
960 save_parse_offset = pkt->parse_offset;
961 res = mdns_read_answer(pkt, &pkt_a, &pkt->authoritative_left);
962 if (res != ERR_OK) {
963 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
964 goto cleanup;
965 }
966 if (mdns_is_answer_to_question(&my_q, &pkt_a)) {
967 /* Add to list */
968 res = mdns_push_answer_to_sorted_list(&pkt_a_list, pkt, save_parse_offset, &pkt_a);
969 if (res != ERR_OK) {
970 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to add answer, skipping probe packet\n"));
971 goto cleanup;
972 }
973 }
974 }
975
976 /* Reinitiate authoritative left */
977 myprobe_inpkt.authoritative_left = myprobe_inpkt.authoritative;
978 pkt->authoritative_left = pkt->authoritative;
979
980 /* Compare pairwise.
981 * - lexicographically later? -> we win, ignore the packet.
982 * - lexicographically earlier? -> we loose, wait one second and retry.
983 * - lexicographically equal? -> no conflict, check other probes.
984 */
985 min = LWIP_MIN(my_a_list.size, pkt_a_list.size);
986 for (i = 0; i < min; i++) {
987 /* Get answer of our own list */
988 myprobe_inpkt.parse_offset = my_a_list.offset[i];
989 res = mdns_read_answer(&myprobe_inpkt, &my_a, &myprobe_inpkt.authoritative_left);
990 if (res != ERR_OK) {
991 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
992 goto cleanup;
993 }
994 /* Get answer of the packets list */
995 pkt->parse_offset = pkt_a_list.offset[i];
996 res = mdns_read_answer(pkt, &pkt_a, &pkt->authoritative_left);
997 if (res != ERR_OK) {
998 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
999 goto cleanup;
1000 }
1001 /* Print both answers for debugging */
1002 mdns_debug_print_answer(pkt, &pkt_a);
1003 mdns_debug_print_answer(&myprobe_inpkt, &my_a);
1004 /* Define the winner */
1005 res = mdns_lexicographical_comparison(&myprobe_inpkt, pkt, &my_a, &pkt_a, &result);
1006 if (res != ERR_OK) {
1007 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to compare answers, skipping probe packet\n"));
1008 goto cleanup;
1009 }
1010 if (result == MDNS_LEXICOGRAPHICAL_LATER) {
1011 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we win, we are lexicographically later\n"));
1012 goto cleanup;
1013 }
1014 else if (result == MDNS_LEXICOGRAPHICAL_EARLIER) {
1015 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we loose, we are lexicographically earlier. 1s timeout started\n"));
1016 /* Increase the number of conflicts occurred */
1017 mdns_conflict_save_time(netif);
1018 /* then restart with 1s delay */
1019 mdns_resp_restart_delay(netif, MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS);
1020 goto cleanup;
1021 }
1022 else {
1023 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: lexicographically equal, so no conclusion\n"));
1024 }
1025 }
1026 /* All compared RR were equal, otherwise we would not be here
1027 * -> check if one of both have more answers to the question */
1028 if (my_a_list.size != pkt_a_list.size) {
1029 if (my_a_list.size > pkt_a_list.size) {
1030 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we win, we have more records answering the probe\n"));
1031 goto cleanup;
1032 }
1033 else {
1034 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we loose, we have less records. 1s timeout started\n"));
1035 /* Increase the number of conflicts occurred */
1036 mdns_conflict_save_time(netif);
1037 /* then restart with 1s delay */
1038 mdns_resp_restart_delay(netif, MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS);
1039 goto cleanup;
1040 }
1041 }
1042 else {
1043 /* There is no conflict on this probe, both devices have the same data
1044 * in the authoritative section. We should still check the other probes
1045 * for conflicts. */
1046 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: no conflict, all records answering the probe are equal\n"));
1047 }
1048 }
1049 /* Evaluate other probes if any. */
1050 /* Reinitiate parse offsets */
1051 pkt->parse_offset = pkt_parse_offset;
1052 myprobe_inpkt.parse_offset = myprobe_parse_offset;
1053 /* Reinitiate questions_left and authoritative_left */
1054 pkt->questions_left = pkt->questions;
1055 pkt->authoritative_left = pkt->authoritative;
1056 myprobe_inpkt.questions_left = myprobe_questions_left;
1057 myprobe_inpkt.authoritative_left = myprobe_inpkt.authoritative;
1058 }
1059
1060 cleanup:
1061 if (myprobe_inpkt.pbuf != NULL) {
1062 pbuf_free(myprobe_inpkt.pbuf);
1063 }
1064 }
1065
1066 /**
1067 * Check the incoming packet and parse all questions
1068 *
1069 * @param netif network interface of incoming packet
1070 * @param pkt incoming packet
1071 * @param reply outgoing message
1072 * @return err_t
1073 */
1074 static err_t
mdns_parse_pkt_questions(struct netif * netif,struct mdns_packet * pkt,struct mdns_outmsg * reply)1075 mdns_parse_pkt_questions(struct netif *netif, struct mdns_packet *pkt,
1076 struct mdns_outmsg *reply)
1077 {
1078 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1079 struct mdns_service *service;
1080 int i;
1081 err_t res;
1082
1083 while (pkt->questions_left) {
1084 struct mdns_question q;
1085
1086 res = mdns_read_question(pkt, &q);
1087 if (res != ERR_OK) {
1088 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping query packet\n"));
1089 return res;
1090 }
1091
1092 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Query for domain "));
1093 mdns_domain_debug_print(&q.info.domain);
1094 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", q.info.type, q.info.klass));
1095
1096 if (q.unicast) {
1097 /* Reply unicast if it is requested in the question */
1098 reply->unicast_reply_requested = 1;
1099 }
1100
1101 reply->host_replies |= check_host(netif, &q.info, &reply->host_reverse_v6_replies);
1102
1103 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1104 service = mdns->services[i];
1105 if (!service) {
1106 continue;
1107 }
1108 reply->serv_replies[i] |= check_service(service, &q.info);
1109 }
1110 }
1111
1112 return ERR_OK;
1113 }
1114
1115 /**
1116 * Check the incoming packet and parse all (known) answers
1117 *
1118 * @param netif network interface of incoming packet
1119 * @param pkt incoming packet
1120 * @param reply outgoing message
1121 * @return err_t
1122 */
1123 static err_t
mdns_parse_pkt_known_answers(struct netif * netif,struct mdns_packet * pkt,struct mdns_outmsg * reply)1124 mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt,
1125 struct mdns_outmsg *reply)
1126 {
1127 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1128 struct mdns_service *service;
1129 int i;
1130 err_t res;
1131
1132 while (pkt->answers_left) {
1133 struct mdns_answer ans;
1134 u8_t rev_v6;
1135 int match;
1136 u32_t rr_ttl = MDNS_TTL_120;
1137
1138 res = mdns_read_answer(pkt, &ans, &pkt->answers_left);
1139 if (res != ERR_OK) {
1140 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n"));
1141 return res;
1142 }
1143
1144 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Known answer for domain "));
1145 mdns_domain_debug_print(&ans.info.domain);
1146 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
1147
1148
1149 if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass == DNS_RRCLASS_ANY) {
1150 /* Skip known answers for ANY type & class */
1151 continue;
1152 }
1153
1154 rev_v6 = 0;
1155 match = reply->host_replies & check_host(netif, &ans.info, &rev_v6);
1156 if (match && (ans.ttl > (rr_ttl / 2))) {
1157 /* The RR in the known answer matches an RR we are planning to send,
1158 * and the TTL is less than half gone.
1159 * If the payload matches we should not send that answer.
1160 */
1161 if (ans.info.type == DNS_RRTYPE_PTR) {
1162 /* Read domain and compare */
1163 struct mdns_domain known_ans, my_ans;
1164 u16_t len;
1165 len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans);
1166 res = mdns_build_host_domain(&my_ans, mdns);
1167 if (len != MDNS_READNAME_ERROR && res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
1168 #if LWIP_IPV4
1169 if (match & REPLY_HOST_PTR_V4) {
1170 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v4 PTR\n"));
1171 reply->host_replies &= ~REPLY_HOST_PTR_V4;
1172 }
1173 #endif
1174 #if LWIP_IPV6
1175 if (match & REPLY_HOST_PTR_V6) {
1176 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v6 PTR\n"));
1177 reply->host_reverse_v6_replies &= ~rev_v6;
1178 if (reply->host_reverse_v6_replies == 0) {
1179 reply->host_replies &= ~REPLY_HOST_PTR_V6;
1180 }
1181 }
1182 #endif
1183 }
1184 } else if (match & REPLY_HOST_A) {
1185 #if LWIP_IPV4
1186 if (ans.rd_length == sizeof(ip4_addr_t) &&
1187 pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) {
1188 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: A\n"));
1189 reply->host_replies &= ~REPLY_HOST_A;
1190 }
1191 #endif
1192 } else if (match & REPLY_HOST_AAAA) {
1193 #if LWIP_IPV6
1194 if (ans.rd_length == sizeof(ip6_addr_p_t) &&
1195 /* TODO this clears all AAAA responses if first addr is set as known */
1196 pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, 0), ans.rd_length) == 0) {
1197 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: AAAA\n"));
1198 reply->host_replies &= ~REPLY_HOST_AAAA;
1199 }
1200 #endif
1201 }
1202 }
1203
1204 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1205 service = mdns->services[i];
1206 if (!service) {
1207 continue;
1208 }
1209 match = reply->serv_replies[i] & check_service(service, &ans.info);
1210 if (match & REPLY_SERVICE_TYPE_PTR) {
1211 rr_ttl = MDNS_TTL_4500;
1212 }
1213 if (match && (ans.ttl > (rr_ttl / 2))) {
1214 /* The RR in the known answer matches an RR we are planning to send,
1215 * and the TTL is less than half gone.
1216 * If the payload matches we should not send that answer.
1217 */
1218 if (ans.info.type == DNS_RRTYPE_PTR) {
1219 /* Read domain and compare */
1220 struct mdns_domain known_ans, my_ans;
1221 u16_t len;
1222 len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans);
1223 if (len != MDNS_READNAME_ERROR) {
1224 if (match & REPLY_SERVICE_TYPE_PTR) {
1225 res = mdns_build_service_domain(&my_ans, service, 0);
1226 if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
1227 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service type PTR\n"));
1228 reply->serv_replies[i] &= ~REPLY_SERVICE_TYPE_PTR;
1229 }
1230 }
1231 if (match & REPLY_SERVICE_NAME_PTR) {
1232 res = mdns_build_service_domain(&my_ans, service, 1);
1233 if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
1234 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service name PTR\n"));
1235 reply->serv_replies[i] &= ~REPLY_SERVICE_NAME_PTR;
1236 }
1237 }
1238 }
1239 } else if (match & REPLY_SERVICE_SRV) {
1240 /* Read and compare to my SRV record */
1241 u16_t field16, len, read_pos;
1242 struct mdns_domain known_ans, my_ans;
1243 read_pos = ans.rd_offset;
1244 do {
1245 /* Check priority field */
1246 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
1247 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) {
1248 break;
1249 }
1250 read_pos += len;
1251 /* Check weight field */
1252 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
1253 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) {
1254 break;
1255 }
1256 read_pos += len;
1257 /* Check port field */
1258 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
1259 if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) {
1260 break;
1261 }
1262 read_pos += len;
1263 /* Check host field */
1264 len = mdns_readname(pkt->pbuf, read_pos, &known_ans);
1265 mdns_build_host_domain(&my_ans, mdns);
1266 if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&known_ans, &my_ans)) {
1267 break;
1268 }
1269 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: SRV\n"));
1270 reply->serv_replies[i] &= ~REPLY_SERVICE_SRV;
1271 } while (0);
1272 } else if (match & REPLY_SERVICE_TXT) {
1273 mdns_prepare_txtdata(service);
1274 if (service->txtdata.length == ans.rd_length &&
1275 pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) {
1276 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: TXT\n"));
1277 reply->serv_replies[i] &= ~REPLY_SERVICE_TXT;
1278 }
1279 }
1280 }
1281 }
1282 }
1283
1284 return ERR_OK;
1285 }
1286
1287 /**
1288 * Check the incoming packet and parse all authoritative answers to see if the
1289 * query is a probe query.
1290 *
1291 * @param netif network interface of incoming packet
1292 * @param pkt incoming packet
1293 * @param reply outgoing message
1294 * @return err_t
1295 */
1296 static err_t
mdns_parse_pkt_authoritative_answers(struct netif * netif,struct mdns_packet * pkt,struct mdns_outmsg * reply)1297 mdns_parse_pkt_authoritative_answers(struct netif *netif, struct mdns_packet *pkt,
1298 struct mdns_outmsg *reply)
1299 {
1300 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1301 struct mdns_service *service;
1302 int i;
1303 err_t res;
1304
1305 while (pkt->authoritative_left) {
1306 struct mdns_answer ans;
1307 u8_t rev_v6;
1308 int match;
1309
1310 res = mdns_read_answer(pkt, &ans, &pkt->authoritative_left);
1311 if (res != ERR_OK) {
1312 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n"));
1313 return res;
1314 }
1315
1316 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Authoritative answer for domain "));
1317 mdns_domain_debug_print(&ans.info.domain);
1318 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
1319
1320
1321 if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass == DNS_RRCLASS_ANY) {
1322 /* Skip known answers for ANY type & class */
1323 continue;
1324 }
1325
1326 rev_v6 = 0;
1327 match = reply->host_replies & check_host(netif, &ans.info, &rev_v6);
1328 if (match) {
1329 reply->probe_query_recv = 1;
1330 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own host info received\n"));
1331 }
1332
1333 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1334 service = mdns->services[i];
1335 if (!service) {
1336 continue;
1337 }
1338 match = reply->serv_replies[i] & check_service(service, &ans.info);
1339
1340 if (match) {
1341 reply->probe_query_recv = 1;
1342 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own service info received\n"));
1343 }
1344 }
1345 }
1346
1347 return ERR_OK;
1348 }
1349
1350 /**
1351 * Add / copy message to delaying message buffer.
1352 *
1353 * @param dest destination msg struct
1354 * @param src source msg struct
1355 */
1356 static void
mdns_add_msg_to_delayed(struct mdns_outmsg * dest,struct mdns_outmsg * src)1357 mdns_add_msg_to_delayed(struct mdns_outmsg *dest, struct mdns_outmsg *src)
1358 {
1359 int i;
1360
1361 dest->host_questions |= src->host_questions;
1362 dest->host_replies |= src->host_replies;
1363 dest->host_reverse_v6_replies |= src->host_reverse_v6_replies;
1364 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1365 dest->serv_questions[i] |= src->serv_questions[i];
1366 dest->serv_replies[i] |= src->serv_replies[i];
1367 }
1368
1369 dest->flags = src->flags;
1370 dest->cache_flush = src->cache_flush;
1371 dest->tx_id = src->tx_id;
1372 dest->legacy_query = src->legacy_query;
1373 }
1374
1375 /**
1376 * Handle question MDNS packet
1377 * - Perform probe tiebreaking when in probing state
1378 * - Parse all questions and set bits what answers to send
1379 * - Clear pending answers if known answers are supplied
1380 * - Define which type of answer is requested
1381 * - Send out packet or put it on hold until after random time
1382 *
1383 * @param pkt incoming packet (in stack)
1384 * @param netif network interface of incoming packet
1385 */
1386 static void
mdns_handle_question(struct mdns_packet * pkt,struct netif * netif)1387 mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
1388 {
1389 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1390 struct mdns_outmsg reply;
1391 u8_t rrs_to_send;
1392 u8_t shared_answer = 0;
1393 u8_t delay_response = 1;
1394 u8_t send_unicast = 0;
1395 u8_t listen_to_QU_bit = 0;
1396 int i;
1397 err_t res;
1398
1399 if ((mdns->state == MDNS_STATE_PROBING) ||
1400 (mdns->state == MDNS_STATE_ANNOUNCE_WAIT)) {
1401 /* Probe Tiebreaking */
1402 /* Check if packet is a probe message */
1403 if ((pkt->questions > 0) && (pkt->answers == 0) &&
1404 (pkt->authoritative > 0) && (pkt->additional == 0)) {
1405 /* This should be a probe message -> call probe handler */
1406 mdns_handle_probe_tiebreaking(netif, pkt);
1407 }
1408 }
1409
1410 if ((mdns->state != MDNS_STATE_COMPLETE) &&
1411 (mdns->state != MDNS_STATE_ANNOUNCING)) {
1412 /* Don't answer questions until we've verified our domains via probing */
1413 /* @todo we should check incoming questions during probing for tiebreaking */
1414 return;
1415 }
1416
1417 memset(&reply, 0, sizeof(struct mdns_outmsg));
1418
1419 /* Parse question */
1420 res = mdns_parse_pkt_questions(netif, pkt, &reply);
1421 if (res != ERR_OK) {
1422 return;
1423 }
1424 /* Parse answers -> count as known answers because it's a question */
1425 res = mdns_parse_pkt_known_answers(netif, pkt, &reply);
1426 if (res != ERR_OK) {
1427 return;
1428 }
1429 if (pkt->next_answer) {
1430 /* Also parse known-answers from additional packets */
1431 struct mdns_packet *pkta = pkt->next_answer;
1432 while (pkta) {
1433 res = mdns_parse_pkt_known_answers(netif, pkta, &reply);
1434 if (res != ERR_OK) {
1435 return;
1436 }
1437 pkta = pkta->next_answer;
1438 }
1439 }
1440 /* Parse authoritative answers -> probing */
1441 /* If it's a probe query, we need to directly answer via unicast. */
1442 res = mdns_parse_pkt_authoritative_answers(netif, pkt, &reply);
1443 if (res != ERR_OK) {
1444 return;
1445 }
1446 /* Ignore additional answers -> do not have any need for them at the moment */
1447 if(pkt->additional) {
1448 LWIP_DEBUGF(MDNS_DEBUG,
1449 ("MDNS: Query contains additional answers -> they are discarded\n"));
1450 }
1451
1452 /* Any replies on question? */
1453 rrs_to_send = reply.host_replies | reply.host_questions;
1454 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1455 rrs_to_send |= reply.serv_replies[i] | reply.serv_questions[i];
1456 }
1457
1458 if (!rrs_to_send) {
1459 /* This case is most common */
1460 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Nothing to answer\n"));
1461 return;
1462 }
1463
1464 reply.flags = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE;
1465
1466 /* Detect if it's a legacy querier asking the question
1467 * How to detect legacy DNS query? (RFC6762 section 6.7)
1468 * - source port != 5353
1469 * - a legacy query can only contain 1 question
1470 */
1471 if (pkt->source_port != LWIP_IANA_PORT_MDNS) {
1472 if (pkt->questions == 1) {
1473 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: request from legacy querier\n"));
1474 reply.legacy_query = 1;
1475 reply.tx_id = pkt->tx_id;
1476 reply.cache_flush = 0;
1477 }
1478 else {
1479 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: ignore query if (src UDP port != 5353) && (!= legacy query)\n"));
1480 return;
1481 }
1482 }
1483 else {
1484 reply.cache_flush = 1;
1485 }
1486
1487 /* Delaying response. (RFC6762 section 6)
1488 * Always delay the response, unicast or multicast, except when:
1489 * - Answering to a single question with a unique answer (not a probe).
1490 * - Answering to a probe query via unicast.
1491 * - Answering to a probe query via multicast if not multicasted within 250ms.
1492 *
1493 * unique answer? -> not if it includes service type or name ptr's
1494 */
1495 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1496 shared_answer |= (reply.serv_replies[i] &
1497 (REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR));
1498 }
1499 if ( ((pkt->questions == 1) && (!shared_answer) && !reply.probe_query_recv)
1500 || (reply.probe_query_recv && reply.unicast_reply_requested)) {
1501 delay_response = 0;
1502 }
1503 #if LWIP_IPV6
1504 if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv
1505 && !reply.unicast_reply_requested && !mdns->ipv6.multicast_probe_timeout) {
1506 delay_response = 0;
1507 }
1508 #endif
1509 #if LWIP_IPV4
1510 if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv
1511 && !reply.unicast_reply_requested && !mdns->ipv4.multicast_probe_timeout) {
1512 delay_response = 0;
1513 }
1514 #endif
1515 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: response %s delayed\n", (delay_response ? "randomly" : "not")));
1516
1517 /* Unicast / multicast response:
1518 * Answering to (m)DNS querier via unicast response.
1519 * When:
1520 * a) Unicast reply requested && recently multicasted 1/4ttl (RFC6762 section 5.4)
1521 * b) Direct unicast query to port 5353 (RFC6762 section 5.5)
1522 * c) Reply to Legacy DNS querier (RFC6762 section 6.7)
1523 * d) A probe message is received requesting unicast (RFC6762 section 6)
1524 */
1525
1526 #if LWIP_IPV6
1527 if ((IP_IS_V6_VAL(pkt->source_addr) && mdns->ipv6.multicast_timeout_25TTL)) {
1528 listen_to_QU_bit = 1;
1529 }
1530 #endif
1531 #if LWIP_IPV4
1532 if ((IP_IS_V4_VAL(pkt->source_addr) && mdns->ipv4.multicast_timeout_25TTL)) {
1533 listen_to_QU_bit = 1;
1534 }
1535 #endif
1536 if ( (reply.unicast_reply_requested && listen_to_QU_bit)
1537 || pkt->recv_unicast
1538 || reply.legacy_query
1539 || (reply.probe_query_recv && reply.unicast_reply_requested)) {
1540 send_unicast = 1;
1541 }
1542 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: send response via %s\n", (send_unicast ? "unicast" : "multicast")));
1543
1544 /* Send out or put on waiting list */
1545 if (delay_response) {
1546 if (send_unicast) {
1547 #if LWIP_IPV6
1548 /* Add answers to IPv6 waiting list if:
1549 * - it's a IPv6 incoming packet
1550 * - no message is in it yet
1551 */
1552 if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.unicast_msg_in_use) {
1553 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to unicast IPv6 waiting list\n"));
1554 SMEMCPY(&mdns->ipv6.delayed_msg_unicast.dest_addr, &pkt->source_addr, sizeof(ip_addr_t));
1555 mdns->ipv6.delayed_msg_unicast.dest_port = pkt->source_port;
1556
1557 mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_unicast, &reply);
1558
1559 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_unicast_msg_delayed_ipv6,
1560 &mdns->ipv6.unicast_msg_in_use);
1561 }
1562 #endif
1563 #if LWIP_IPV4
1564 /* Add answers to IPv4 waiting list if:
1565 * - it's a IPv4 incoming packet
1566 * - no message is in it yet
1567 */
1568 if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.unicast_msg_in_use) {
1569 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to unicast IPv4 waiting list\n"));
1570 SMEMCPY(&mdns->ipv4.delayed_msg_unicast.dest_addr, &pkt->source_addr, sizeof(ip_addr_t));
1571 mdns->ipv4.delayed_msg_unicast.dest_port = pkt->source_port;
1572
1573 mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_unicast, &reply);
1574
1575 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_unicast_msg_delayed_ipv4,
1576 &mdns->ipv4.unicast_msg_in_use);
1577 }
1578 #endif
1579 }
1580 else {
1581 #if LWIP_IPV6
1582 /* Add answers to IPv6 waiting list if:
1583 * - it's a IPv6 incoming packet
1584 * - the 1 second timeout is passed (RFC6762 section 6)
1585 * - and it's not a probe packet
1586 * Or if:
1587 * - it's a IPv6 incoming packet
1588 * - and it's a probe packet
1589 */
1590 if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout
1591 && !reply.probe_query_recv) {
1592 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv6 waiting list\n"));
1593
1594 mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply);
1595
1596 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv6,
1597 &mdns->ipv6.multicast_msg_waiting);
1598 }
1599 else if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv) {
1600 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv6 waiting list\n"));
1601
1602 mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply);
1603
1604 mdns->ipv6.multicast_msg_waiting = 1;
1605 }
1606 #endif
1607 #if LWIP_IPV4
1608 /* Add answers to IPv4 waiting list if:
1609 * - it's a IPv4 incoming packet
1610 * - the 1 second timeout is passed (RFC6762 section 6)
1611 * - and it's not a probe packet
1612 * Or if:
1613 * - it's a IPv4 incoming packet
1614 * - and it's a probe packet
1615 */
1616 if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout
1617 && !reply.probe_query_recv) {
1618 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv4 waiting list\n"));
1619
1620 mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply);
1621
1622 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv4,
1623 &mdns->ipv4.multicast_msg_waiting);
1624 }
1625 else if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv) {
1626 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv4 waiting list\n"));
1627
1628 mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply);
1629
1630 mdns->ipv4.multicast_msg_waiting = 1;
1631 }
1632 #endif
1633 }
1634 }
1635 else {
1636 if (send_unicast) {
1637 /* Copy source IP/port to use when responding unicast */
1638 SMEMCPY(&reply.dest_addr, &pkt->source_addr, sizeof(ip_addr_t));
1639 reply.dest_port = pkt->source_port;
1640 /* send answer directly via unicast */
1641 res = mdns_send_outpacket(&reply, netif);
1642 if (res != ERR_OK) {
1643 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Unicast answer could not be send\n"));
1644 }
1645 else {
1646 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Unicast answer send successfully\n"));
1647 }
1648 return;
1649 }
1650 else {
1651 /* Set IP/port to use when responding multicast */
1652 #if LWIP_IPV6
1653 if (IP_IS_V6_VAL(pkt->source_addr)) {
1654 if (mdns->ipv6.multicast_timeout && !reply.probe_query_recv) {
1655 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\n"));
1656 return;
1657 }
1658 SMEMCPY(&reply.dest_addr, &v6group, sizeof(ip_addr_t));
1659 }
1660 #endif
1661 #if LWIP_IPV4
1662 if (IP_IS_V4_VAL(pkt->source_addr)) {
1663 if (mdns->ipv4.multicast_timeout && !reply.probe_query_recv) {
1664 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\n"));
1665 return;
1666 }
1667 SMEMCPY(&reply.dest_addr, &v4group, sizeof(ip_addr_t));
1668 }
1669 #endif
1670 reply.dest_port = LWIP_IANA_PORT_MDNS;
1671 /* send answer directly via multicast */
1672 res = mdns_send_outpacket(&reply, netif);
1673 if (res != ERR_OK) {
1674 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer could not be send\n"));
1675 }
1676 else {
1677 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer send successfully\n"));
1678 #if LWIP_IPV6
1679 if (IP_IS_V6_VAL(pkt->source_addr)) {
1680 mdns_start_multicast_timeouts_ipv6(netif);
1681 }
1682 #endif
1683 #if LWIP_IPV4
1684 if (IP_IS_V4_VAL(pkt->source_addr)) {
1685 mdns_start_multicast_timeouts_ipv4(netif);
1686 }
1687 #endif
1688 }
1689 return;
1690 }
1691 }
1692 }
1693
1694 /**
1695 * Handle truncated question MDNS packet
1696 * - Called by timer
1697 * - Call mdns_handle_question
1698 * - Do cleanup
1699 *
1700 * @param arg incoming packet (in pool)
1701 */
1702 static void
mdns_handle_tc_question(void * arg)1703 mdns_handle_tc_question(void *arg)
1704 {
1705 struct mdns_packet *pkt = (struct mdns_packet *)arg;
1706 struct netif *from = netif_get_by_index(pkt->pbuf->if_idx);
1707 /* timer as elapsed, now handle this question */
1708 mdns_handle_question(pkt, from);
1709 /* remove from pending list */
1710 if (pending_tc_questions == pkt) {
1711 pending_tc_questions = pkt->next_tc_question;
1712 }
1713 else {
1714 struct mdns_packet *prev = pending_tc_questions;
1715 while (prev && prev->next_tc_question != pkt) {
1716 prev = prev->next_tc_question;
1717 }
1718 LWIP_ASSERT("pkt not found in pending_tc_questions list", prev != NULL);
1719 prev->next_tc_question = pkt->next_tc_question;
1720 }
1721 /* free linked answers and this question */
1722 while (pkt->next_answer) {
1723 struct mdns_packet *ans = pkt->next_answer;
1724 pkt->next_answer = ans->next_answer;
1725 pbuf_free(ans->pbuf);
1726 LWIP_MEMPOOL_FREE(MDNS_PKTS, ans);
1727 }
1728 pbuf_free(pkt->pbuf);
1729 LWIP_MEMPOOL_FREE(MDNS_PKTS, pkt);
1730 }
1731
1732 /**
1733 * Save time when a probe conflict occurs:
1734 * - Check if we exceeded the maximum of 15 conflicts in 10seconds.
1735 *
1736 * @param netif network interface on which the conflict occurred.
1737 */
1738 static void
mdns_conflict_save_time(struct netif * netif)1739 mdns_conflict_save_time(struct netif *netif)
1740 {
1741 struct mdns_host* mdns = NETIF_TO_HOST(netif);
1742 int i;
1743 u32_t diff;
1744 u8_t index2;
1745
1746 /* Increase the number of conflicts occurred */
1747 mdns->num_conflicts++;
1748 mdns->conflict_time[mdns->index] = sys_now();
1749 /* Print timestamp list */
1750 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: conflict timestamp list, insert index = %d\n", mdns->index));
1751 for(i = 0; i < MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT; i++) {
1752 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: time no. %d = %"U32_F"\n", i, mdns->conflict_time[i]));
1753 }
1754 /* Check if we had enough conflicts, minimum 15 */
1755 if (mdns->num_conflicts >= MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT) {
1756 /* Get the index to the oldest timestamp */
1757 index2 = (mdns->index + 1) % MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT;
1758 /* Compare the oldest vs newest time stamp */
1759 diff = mdns->conflict_time[mdns->index] - mdns->conflict_time[index2];
1760 /* If they are less then 10 seconds apart, initiate rate limit */
1761 if (diff < MDNS_PROBE_MAX_CONFLICTS_TIME_WINDOW) {
1762 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: probe rate limit enabled\n"));
1763 mdns->rate_limit_activated = 1;
1764 }
1765 }
1766 /* Increase index */
1767 mdns->index = (mdns->index + 1) % MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT;
1768 }
1769
1770 /**
1771 * Handle a probe conflict:
1772 * - Check if we exceeded the maximum of 15 conflicts in 10seconds.
1773 * - Let the user know there is a conflict.
1774 *
1775 * @param netif network interface on which the conflict occurred.
1776 * @param slot service index +1 on which the conflict occurred (0 indicate hostname conflict).
1777 */
1778 static void
mdns_probe_conflict(struct netif * netif,s8_t slot)1779 mdns_probe_conflict(struct netif *netif, s8_t slot)
1780 {
1781 /* Increase the number of conflicts occurred and check rate limiting */
1782 mdns_conflict_save_time(netif);
1783
1784 /* Disable currently running probe / announce timer */
1785 sys_untimeout(mdns_probe_and_announce, netif);
1786
1787 /* Inform the host on the conflict, if a callback is set */
1788 if (mdns_name_result_cb != NULL) {
1789 mdns_name_result_cb(netif, MDNS_PROBING_CONFLICT, slot);
1790 }
1791 /* TODO: rename and call restart if no mdns_name_result_cb was set? */
1792 }
1793
1794 /**
1795 * Loockup matching request for response MDNS packet
1796 */
1797 #if LWIP_MDNS_SEARCH
1798 static struct mdns_request *
mdns_lookup_request(struct mdns_rr_info * rr)1799 mdns_lookup_request(struct mdns_rr_info *rr)
1800 {
1801 int i;
1802 /* search originating request */
1803 for (i = 0; i < MDNS_MAX_REQUESTS; i++) {
1804 if ((mdns_requests[i].result_fn != NULL) &&
1805 (check_request(&mdns_requests[i], rr) != 0)) {
1806 return &mdns_requests[i];
1807 }
1808 }
1809 return NULL;
1810 }
1811 #endif
1812
1813 /**
1814 * Handle response MDNS packet:
1815 * - Handle responses on probe query
1816 * - Perform conflict resolution on every packet (RFC6762 section 9)
1817 *
1818 * @param pkt incoming packet
1819 * @param netif network interface on which packet was received
1820 */
1821 static void
mdns_handle_response(struct mdns_packet * pkt,struct netif * netif)1822 mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
1823 {
1824 struct mdns_host* mdns = NETIF_TO_HOST(netif);
1825 u16_t total_answers_left;
1826 #if LWIP_MDNS_SEARCH
1827 struct mdns_request *req = NULL;
1828 s8_t first = 1;
1829 #endif
1830
1831 /* Ignore responses with a source port different from 5353
1832 * (LWIP_IANA_PORT_MDNS) -> RFC6762 section 6 */
1833 if (pkt->source_port != LWIP_IANA_PORT_MDNS) {
1834 return;
1835 }
1836
1837 /* Ignore all questions */
1838 while (pkt->questions_left) {
1839 struct mdns_question q;
1840 err_t res;
1841 res = mdns_read_question(pkt, &q);
1842 if (res != ERR_OK) {
1843 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping response packet\n"));
1844 return;
1845 }
1846 #if LWIP_MDNS_SEARCH
1847 else {
1848 req = mdns_lookup_request(&q.info);
1849 }
1850 #endif
1851 }
1852 /* We need to check all resource record sections: answers, authoritative and additional */
1853 total_answers_left = pkt->answers_left + pkt->authoritative_left + pkt->additional_left;
1854 while (total_answers_left) {
1855 struct mdns_answer ans;
1856 err_t res;
1857
1858 res = mdns_read_answer(pkt, &ans, &total_answers_left);
1859 if (res != ERR_OK) {
1860 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping response packet\n"));
1861 return;
1862 }
1863
1864 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Answer for domain "));
1865 mdns_domain_debug_print(&ans.info.domain);
1866 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
1867
1868 if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass != DNS_RRCLASS_IN) {
1869 /* Skip answers for ANY type or if class != IN */
1870 continue;
1871 }
1872
1873 #if LWIP_MDNS_SEARCH
1874 if (req && req->only_ptr) {
1875 /* Need to recheck that this answer match request that match previous answer */
1876 if (memcmp (req->service.name, ans.info.domain.name, req->service.length) != 0)
1877 req = NULL;
1878 }
1879 if (!req) {
1880 /* Try hard to search matching request */
1881 req = mdns_lookup_request(&ans.info);
1882 }
1883 if (req && req->result_fn) {
1884 u16_t offset;
1885 struct pbuf *p;
1886 int flags = (first ? MDNS_SEARCH_RESULT_FIRST : 0) |
1887 (!total_answers_left ? MDNS_SEARCH_RESULT_LAST : 0);
1888 if (req->only_ptr) {
1889 if (ans.info.type != DNS_RRTYPE_PTR)
1890 continue; /* Ignore non matching answer type */
1891 flags = MDNS_SEARCH_RESULT_FIRST | MDNS_SEARCH_RESULT_LAST;
1892 }
1893 p = pbuf_skip(pkt->pbuf, ans.rd_offset, &offset);
1894 if (p == NULL) {
1895 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Malformed response packet, aborting\n"));
1896 return;
1897 }
1898 if (ans.info.type == DNS_RRTYPE_PTR || ans.info.type == DNS_RRTYPE_SRV) {
1899 /* Those RR types have compressed domain name. Must uncompress here,
1900 since cannot be done without pbuf. */
1901 struct {
1902 u16_t values[3]; /* SRV: Prio, Weight, Port */
1903 struct mdns_domain dom; /* PTR & SRV: Domain (uncompressed) */
1904 } data;
1905 u16_t off = (ans.info.type == DNS_RRTYPE_SRV ? 6 : 0);
1906 u16_t len = mdns_readname(pkt->pbuf, ans.rd_offset + off, &data.dom);
1907 if (len == MDNS_READNAME_ERROR) {
1908 /* Ensure result_fn is called anyway, just copy failed domain as is */
1909 data.dom.length = ans.rd_length - off;
1910 memcpy(&data.dom, (const char *)p->payload + offset + off, data.dom.length);
1911 }
1912 /* Adjust len/off according RR type */
1913 if (ans.info.type == DNS_RRTYPE_SRV) {
1914 memcpy(&data, (const char *)p->payload + offset, 6);
1915 len = data.dom.length + 6;
1916 off = 0;
1917 } else {
1918 len = data.dom.length;
1919 off = 6;
1920 }
1921 req->result_fn(&ans, (const char *)&data + off, len, flags, req->arg);
1922 } else {
1923 /* Direct call result_fn with varpart pointing in pbuf payload */
1924 req->result_fn(&ans, (const char *)p->payload + offset, ans.rd_length, flags, req->arg);
1925 }
1926 first = 0;
1927 }
1928 #endif
1929
1930 /* "Conflicting Multicast DNS responses received *before* the first probe
1931 * packet is sent MUST be silently ignored" so drop answer if we haven't
1932 * started probing yet. */
1933 if ((mdns->state == MDNS_STATE_PROBING) ||
1934 (mdns->state == MDNS_STATE_ANNOUNCE_WAIT)) {
1935 struct mdns_domain domain;
1936 u8_t i;
1937
1938 res = mdns_build_host_domain(&domain, mdns);
1939 if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
1940 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches host domain!\n"));
1941 mdns_probe_conflict(netif, 0);
1942 break;
1943 }
1944
1945 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1946 struct mdns_service* service = mdns->services[i];
1947 if (!service) {
1948 continue;
1949 }
1950 res = mdns_build_service_domain(&domain, service, 1);
1951 if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) {
1952 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches service domain!\n"));
1953 mdns_probe_conflict(netif, i + 1);
1954 break;
1955 }
1956 }
1957 if (i < MDNS_MAX_SERVICES)
1958 break;
1959 }
1960 /* Perform conflict resolution (RFC6762 section 9):
1961 * We assume a conflict if the hostname or service name matches the answers
1962 * domain. Only if the rdata matches exactly we reset our assumption to no
1963 * conflict. As stated in the RFC:
1964 * What may be considered inconsistent is context sensitive, except that
1965 * resource records with identical rdata are never considered inconsistent,
1966 * even if they originate from different hosts.
1967 */
1968 else if ((mdns->state == MDNS_STATE_ANNOUNCING) ||
1969 (mdns->state == MDNS_STATE_COMPLETE)) {
1970 struct mdns_domain domain;
1971 u8_t i;
1972 u8_t conflict = 0;
1973
1974 /* Evaluate unique hostname records -> A and AAAA */
1975 res = mdns_build_host_domain(&domain, mdns);
1976 if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
1977 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches host domain, assuming conflict\n"));
1978 /* This means a conflict has taken place, except when the packet contains
1979 * exactly the same rdata. */
1980 conflict = 1;
1981 /* Evaluate rdata -> to see if it's a copy of our own data */
1982 if (ans.info.type == DNS_RRTYPE_A) {
1983 #if LWIP_IPV4
1984 if (ans.rd_length == sizeof(ip4_addr_t) &&
1985 pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) {
1986 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own IPv4 address record -> no conflict\n"));
1987 conflict = 0;
1988 }
1989 #endif
1990 }
1991 else if (ans.info.type == DNS_RRTYPE_AAAA) {
1992 #if LWIP_IPV6
1993 if (ans.rd_length == sizeof(ip6_addr_p_t)) {
1994 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1995 if (pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, i), ans.rd_length) == 0) {
1996 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own iPv6 address record, num = %d -> no conflict\n",i));
1997 conflict = 0;
1998 }
1999 }
2000 }
2001 #endif
2002 }
2003 }
2004 /* Evaluate unique service name records -> SRV and TXT */
2005 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2006 struct mdns_service* service = mdns->services[i];
2007 if (!service) {
2008 continue;
2009 }
2010 res = mdns_build_service_domain(&domain, service, 1);
2011 if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) {
2012 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches service domain, assuming conflict\n"));
2013 /* This means a conflict has taken place, except when the packet contains
2014 * exactly the same rdata. */
2015 conflict = 1;
2016 /* Evaluate rdata -> to see if it's a copy of our own data */
2017 if (ans.info.type == DNS_RRTYPE_SRV) {
2018 /* Read and compare to with our SRV record */
2019 u16_t field16, len, read_pos;
2020 struct mdns_domain srv_ans, my_ans;
2021 read_pos = ans.rd_offset;
2022 do {
2023 /* Check priority field */
2024 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
2025 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) {
2026 break;
2027 }
2028 read_pos += len;
2029 /* Check weight field */
2030 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
2031 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) {
2032 break;
2033 }
2034 read_pos += len;
2035 /* Check port field */
2036 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
2037 if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) {
2038 break;
2039 }
2040 read_pos += len;
2041 /* Check host field */
2042 len = mdns_readname(pkt->pbuf, read_pos, &srv_ans);
2043 mdns_build_host_domain(&my_ans, mdns);
2044 if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&srv_ans, &my_ans)) {
2045 break;
2046 }
2047 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own SRV record -> no conflict\n"));
2048 conflict = 0;
2049 } while (0);
2050 } else if (ans.info.type == DNS_RRTYPE_TXT) {
2051 mdns_prepare_txtdata(service);
2052 if (service->txtdata.length == ans.rd_length &&
2053 pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) {
2054 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own TXT record -> no conflict\n"));
2055 conflict = 0;
2056 }
2057 }
2058 }
2059 }
2060 if (conflict != 0) {
2061 /* Reset host to probing to reconfirm uniqueness */
2062 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: Conflict resolution -> reset to probing state\n"));
2063 mdns_resp_restart(netif);
2064 break;
2065 }
2066 }
2067 }
2068 /* Clear all xxx_left variables because we parsed all answers */
2069 pkt->answers_left = 0;
2070 pkt->authoritative_left = 0;
2071 pkt->additional_left = 0;
2072 }
2073
2074 /**
2075 * Receive input function for MDNS packets.
2076 * Handles both IPv4 and IPv6 UDP pcbs.
2077 */
2078 static void
mdns_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)2079 mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
2080 {
2081 struct dns_hdr hdr;
2082 struct mdns_packet packet;
2083 struct netif *recv_netif = ip_current_input_netif();
2084 u16_t offset = 0;
2085
2086 LWIP_UNUSED_ARG(arg);
2087 LWIP_UNUSED_ARG(pcb);
2088
2089 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Received IPv%d MDNS packet, len %d\n", IP_IS_V6(addr) ? 6 : 4, p->tot_len));
2090
2091 if (NETIF_TO_HOST(recv_netif) == NULL) {
2092 /* From netif not configured for MDNS */
2093 goto dealloc;
2094 }
2095
2096 if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, offset) < SIZEOF_DNS_HDR) {
2097 /* Too small */
2098 goto dealloc;
2099 }
2100 offset += SIZEOF_DNS_HDR;
2101
2102 if (DNS_HDR_GET_OPCODE(&hdr)) {
2103 /* Ignore non-standard queries in multicast packets (RFC 6762, section 18.3) */
2104 goto dealloc;
2105 }
2106
2107 memset(&packet, 0, sizeof(packet));
2108 SMEMCPY(&packet.source_addr, addr, sizeof(packet.source_addr));
2109 packet.source_port = port;
2110 packet.pbuf = p;
2111 packet.parse_offset = offset;
2112 packet.tx_id = lwip_ntohs(hdr.id);
2113 packet.questions = packet.questions_left = lwip_ntohs(hdr.numquestions);
2114 packet.answers = packet.answers_left = lwip_ntohs(hdr.numanswers);
2115 packet.authoritative = packet.authoritative_left = lwip_ntohs(hdr.numauthrr);
2116 packet.additional = packet.additional_left = lwip_ntohs(hdr.numextrarr);
2117
2118 /* Source address check (RFC6762 section 11) -> for responses.
2119 * Source address check (RFC6762 section 5.5) -> for queries.
2120 * When the dest addr == multicast addr we know the packet originated on that
2121 * link. If not, we need to check the source address. We only accept queries
2122 * that originated on the link. Others are discarded.
2123 */
2124 #if LWIP_IPV6
2125 if (IP_IS_V6(ip_current_dest_addr())) {
2126 /* instead of having one 'v6group' per netif, just compare zoneless here */
2127 if (!ip_addr_zoneless_eq(ip_current_dest_addr(), &v6group)) {
2128 packet.recv_unicast = 1;
2129
2130 if (ip6_addr_ismulticast_global(ip_2_ip6(ip_current_src_addr()))
2131 || ip6_addr_isglobal(ip_2_ip6(ip_current_src_addr()))) {
2132 goto dealloc;
2133 }
2134 }
2135 }
2136 #endif
2137 #if LWIP_IPV4
2138 if (!IP_IS_V6(ip_current_dest_addr())) {
2139 if (!ip_addr_eq(ip_current_dest_addr(), &v4group)) {
2140 packet.recv_unicast = 1;
2141
2142 if (!ip4_addr_net_eq(ip_2_ip4(ip_current_src_addr()),
2143 netif_ip4_addr(recv_netif),
2144 netif_ip4_netmask(recv_netif))){
2145 goto dealloc;
2146 }
2147 }
2148 }
2149 #endif
2150
2151 if (hdr.flags1 & DNS_FLAG1_RESPONSE) {
2152 mdns_handle_response(&packet, recv_netif);
2153 } else {
2154 if (packet.questions && hdr.flags1 & DNS_FLAG1_TRUNC) {
2155 /* this is a new truncated question */
2156 struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS);
2157 if (!pkt)
2158 goto dealloc; /* don't reply truncated question if alloc error */
2159 SMEMCPY(pkt, &packet, sizeof(packet));
2160 /* insert this question in pending list */
2161 pkt->next_tc_question = pending_tc_questions;
2162 pending_tc_questions = pkt;
2163 /* question with truncated flags, need to wait 400-500ms before replying */
2164 sys_timeout(MDNS_RESPONSE_TC_DELAY_MS, mdns_handle_tc_question, pkt);
2165 /* return without dealloc pbuf */
2166 return;
2167 }
2168 else if (!packet.questions && packet.answers && pending_tc_questions) {
2169 /* this packet is a known-answer packet for a truncated question previously received */
2170 struct mdns_packet *q = pending_tc_questions;
2171 while (q) {
2172 if ((packet.source_port == q->source_port) &&
2173 ip_addr_eq(&packet.source_addr, &q->source_addr))
2174 break;
2175 q = q->next_tc_question;
2176 }
2177 if (q) {
2178 /* found question from the same source */
2179 struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS);
2180 if (!pkt)
2181 goto dealloc; /* don't reply truncated question if alloc error */
2182 SMEMCPY(pkt, &packet, sizeof(packet));
2183 /* insert this known-ansert in question */
2184 pkt->next_answer = q->next_answer;
2185 q->next_answer = pkt;
2186 /* nothing more to do */
2187 return;
2188 }
2189 }
2190 /* if previous tests fail, handle this question normally */
2191 mdns_handle_question(&packet, recv_netif);
2192 }
2193
2194 dealloc:
2195 pbuf_free(p);
2196 }
2197
2198 #if LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK
2199 static void
mdns_netif_ext_status_callback(struct netif * netif,netif_nsc_reason_t reason,const netif_ext_callback_args_t * args)2200 mdns_netif_ext_status_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args)
2201 {
2202 LWIP_UNUSED_ARG(args);
2203
2204 /* MDNS enabled on netif? */
2205 if (NETIF_TO_HOST(netif) == NULL) {
2206 return;
2207 }
2208
2209 if (reason & LWIP_NSC_STATUS_CHANGED) {
2210 if (args->status_changed.state != 0) {
2211 mdns_resp_restart(netif);
2212 }
2213 /* TODO: send goodbye message */
2214 }
2215 if (reason & LWIP_NSC_LINK_CHANGED) {
2216 if (args->link_changed.state != 0) {
2217 mdns_resp_restart(netif);
2218 }
2219 }
2220 if (reason & (LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_GATEWAY_CHANGED |
2221 LWIP_NSC_IPV4_NETMASK_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED |
2222 LWIP_NSC_IPV6_SET | LWIP_NSC_IPV6_ADDR_STATE_CHANGED)) {
2223 mdns_resp_restart(netif);
2224 }
2225 }
2226 #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK */
2227
2228 static void
mdns_define_probe_rrs_to_send(struct netif * netif,struct mdns_outmsg * outmsg)2229 mdns_define_probe_rrs_to_send(struct netif *netif, struct mdns_outmsg *outmsg)
2230 {
2231 struct mdns_host *mdns = NETIF_TO_HOST(netif);
2232 int i;
2233
2234 memset(outmsg, 0, sizeof(struct mdns_outmsg));
2235
2236 /* Add unicast questions with rtype ANY for all our desired records */
2237 outmsg->host_questions = QUESTION_PROBE_HOST_ANY;
2238
2239 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2240 struct mdns_service* service = mdns->services[i];
2241 if (!service) {
2242 continue;
2243 }
2244 outmsg->serv_questions[i] = QUESTION_PROBE_SERVICE_NAME_ANY;
2245 }
2246
2247 /* Add answers to the questions above into the authority section for tiebreaking */
2248 #if LWIP_IPV4
2249 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
2250 outmsg->host_replies = REPLY_HOST_A;
2251 }
2252 #endif
2253 #if LWIP_IPV6
2254 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
2255 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
2256 outmsg->host_replies |= REPLY_HOST_AAAA;
2257 }
2258 }
2259 #endif
2260
2261 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2262 struct mdns_service *serv = mdns->services[i];
2263 if (serv) {
2264 outmsg->serv_replies[i] = REPLY_SERVICE_SRV;
2265 }
2266 }
2267 }
2268
2269 static err_t
mdns_send_probe(struct netif * netif,const ip_addr_t * destination)2270 mdns_send_probe(struct netif* netif, const ip_addr_t *destination)
2271 {
2272 struct mdns_outmsg outmsg;
2273
2274 mdns_define_probe_rrs_to_send(netif, &outmsg);
2275
2276 outmsg.tx_id = 0;
2277 outmsg.dest_port = LWIP_IANA_PORT_MDNS;
2278 SMEMCPY(&outmsg.dest_addr, destination, sizeof(outmsg.dest_addr));
2279 return mdns_send_outpacket(&outmsg, netif);
2280 }
2281
2282 /**
2283 * Timer callback for probing and announcing on the network.
2284 */
2285 static void
mdns_probe_and_announce(void * arg)2286 mdns_probe_and_announce(void* arg)
2287 {
2288 struct netif *netif = (struct netif *)arg;
2289 struct mdns_host* mdns = NETIF_TO_HOST(netif);
2290 u32_t announce_delay;
2291
2292
2293 switch (mdns->state) {
2294 case MDNS_STATE_OFF:
2295 case MDNS_STATE_PROBE_WAIT:
2296 case MDNS_STATE_PROBING:
2297 #if LWIP_IPV4
2298 /*if ipv4 wait with probing until address is set*/
2299 if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) &&
2300 mdns_send_probe(netif, &v4group) == ERR_OK)
2301 #endif
2302 {
2303 #if LWIP_IPV6
2304 if (mdns_send_probe(netif, &v6group) == ERR_OK)
2305 #endif
2306 {
2307 mdns->state = MDNS_STATE_PROBING;
2308 mdns->sent_num++;
2309 }
2310 }
2311
2312 if (mdns->sent_num >= MDNS_PROBE_COUNT) {
2313 mdns->state = MDNS_STATE_ANNOUNCE_WAIT;
2314 mdns->sent_num = 0;
2315 }
2316
2317 if (mdns->sent_num && mdns->rate_limit_activated == 1) {
2318 /* delay second probe if rate limiting activated */
2319 sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif);
2320 }
2321 else {
2322 sys_timeout(MDNS_PROBE_DELAY_MS, mdns_probe_and_announce, netif);
2323 }
2324 break;
2325 case MDNS_STATE_ANNOUNCE_WAIT:
2326 case MDNS_STATE_ANNOUNCING:
2327 if (mdns->sent_num == 0) {
2328 /* probing was successful, announce all records */
2329 mdns->state = MDNS_STATE_ANNOUNCING;
2330 /* Reset rate limit max probe conflict timeout flag */
2331 mdns->rate_limit_activated = 0;
2332 /* Let the client know probing was successful */
2333 if (mdns_name_result_cb != NULL) {
2334 mdns_name_result_cb(netif, MDNS_PROBING_SUCCESSFUL, 0);
2335 }
2336 }
2337
2338 mdns_resp_announce(netif);
2339 mdns->sent_num++;
2340
2341 if (mdns->sent_num >= MDNS_ANNOUNCE_COUNT) {
2342 /* Announcing and probing complete */
2343 mdns->state = MDNS_STATE_COMPLETE;
2344 mdns->sent_num = 0;
2345 }
2346 else {
2347 announce_delay = MDNS_ANNOUNCE_DELAY_MS * (1 << (mdns->sent_num - 1));
2348 sys_timeout(announce_delay, mdns_probe_and_announce, netif);
2349 }
2350 break;
2351 case MDNS_STATE_COMPLETE:
2352 default:
2353 /* Do nothing */
2354 break;
2355 }
2356 }
2357
2358 /**
2359 * @ingroup mdns
2360 * Activate MDNS responder for a network interface.
2361 * @param netif The network interface to activate.
2362 * @param hostname Name to use. Queries for <hostname>.local will be answered
2363 * with the IP addresses of the netif. The hostname will be copied, the
2364 * given pointer can be on the stack.
2365 * @return ERR_OK if netif was added, an err_t otherwise
2366 */
2367 err_t
mdns_resp_add_netif(struct netif * netif,const char * hostname)2368 mdns_resp_add_netif(struct netif *netif, const char *hostname)
2369 {
2370 err_t res;
2371 struct mdns_host *mdns;
2372
2373 LWIP_ASSERT_CORE_LOCKED();
2374 LWIP_ERROR("mdns_resp_add_netif: netif != NULL", (netif != NULL), return ERR_VAL);
2375 LWIP_ERROR("mdns_resp_add_netif: Hostname too long", (strlen(hostname) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2376
2377 LWIP_ASSERT("mdns_resp_add_netif: Double add", NETIF_TO_HOST(netif) == NULL);
2378 mdns = (struct mdns_host *) mem_calloc(1, sizeof(struct mdns_host));
2379 LWIP_ERROR("mdns_resp_add_netif: Alloc failed", (mdns != NULL), return ERR_MEM);
2380
2381 netif_set_client_data(netif, mdns_netif_client_id, mdns);
2382
2383 MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(hostname)));
2384
2385 /* Init delayed message structs with address and port */
2386 #if LWIP_IPV4
2387 mdns->ipv4.delayed_msg_multicast.dest_port = LWIP_IANA_PORT_MDNS;
2388 SMEMCPY(&mdns->ipv4.delayed_msg_multicast.dest_addr, &v4group,
2389 sizeof(ip_addr_t));
2390 #endif
2391
2392 #if LWIP_IPV6
2393 mdns->ipv6.delayed_msg_multicast.dest_port = LWIP_IANA_PORT_MDNS;
2394 SMEMCPY(&mdns->ipv6.delayed_msg_multicast.dest_addr, &v6group,
2395 sizeof(ip_addr_t));
2396 #endif
2397
2398 /* Join multicast groups */
2399 #if LWIP_IPV4
2400 res = igmp_joingroup_netif(netif, ip_2_ip4(&v4group));
2401 if (res != ERR_OK) {
2402 goto cleanup;
2403 }
2404 #endif
2405 #if LWIP_IPV6
2406 res = mld6_joingroup_netif(netif, ip_2_ip6(&v6group));
2407 if (res != ERR_OK) {
2408 goto cleanup;
2409 }
2410 #endif
2411
2412 mdns_resp_restart(netif);
2413
2414 return ERR_OK;
2415
2416 cleanup:
2417 mem_free(mdns);
2418 netif_set_client_data(netif, mdns_netif_client_id, NULL);
2419 return res;
2420 }
2421
2422 /**
2423 * @ingroup mdns
2424 * Stop responding to MDNS queries on this interface, leave multicast groups,
2425 * and free the helper structure and any of its services.
2426 * @param netif The network interface to remove.
2427 * @return ERR_OK if netif was removed, an err_t otherwise
2428 */
2429 err_t
mdns_resp_remove_netif(struct netif * netif)2430 mdns_resp_remove_netif(struct netif *netif)
2431 {
2432 int i;
2433 struct mdns_host *mdns;
2434
2435 LWIP_ASSERT_CORE_LOCKED();
2436 LWIP_ASSERT("mdns_resp_remove_netif: Null pointer", netif);
2437 mdns = NETIF_TO_HOST(netif);
2438 LWIP_ERROR("mdns_resp_remove_netif: Not an active netif", (mdns != NULL), return ERR_VAL);
2439
2440 sys_untimeout(mdns_probe_and_announce, netif);
2441
2442 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2443 struct mdns_service *service = mdns->services[i];
2444 if (service) {
2445 mem_free(service);
2446 }
2447 }
2448
2449 /* Leave multicast groups */
2450 #if LWIP_IPV4
2451 igmp_leavegroup_netif(netif, ip_2_ip4(&v4group));
2452 #endif
2453 #if LWIP_IPV6
2454 mld6_leavegroup_netif(netif, ip_2_ip6(&v6group));
2455 #endif
2456
2457 mem_free(mdns);
2458 netif_set_client_data(netif, mdns_netif_client_id, NULL);
2459 return ERR_OK;
2460 }
2461
2462 /**
2463 * @ingroup mdns
2464 * Update MDNS hostname for a network interface.
2465 * @param netif The network interface to activate.
2466 * @param hostname Name to use. Queries for <hostname>.local will be answered
2467 * with the IP addresses of the netif. The hostname will be copied, the
2468 * given pointer can be on the stack.
2469 * @return ERR_OK if name could be set on netif, an err_t otherwise
2470 */
2471 err_t
mdns_resp_rename_netif(struct netif * netif,const char * hostname)2472 mdns_resp_rename_netif(struct netif *netif, const char *hostname)
2473 {
2474 struct mdns_host *mdns;
2475 size_t len;
2476
2477 LWIP_ASSERT_CORE_LOCKED();
2478 len = strlen(hostname);
2479 LWIP_ERROR("mdns_resp_rename_netif: netif != NULL", (netif != NULL), return ERR_VAL);
2480 LWIP_ERROR("mdns_resp_rename_netif: Hostname too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2481 mdns = NETIF_TO_HOST(netif);
2482 LWIP_ERROR("mdns_resp_rename_netif: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2483
2484 MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, len));
2485 mdns->name[len] = '\0'; /* null termination in case new name is shorter than previous */
2486
2487 mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS);
2488
2489 return ERR_OK;
2490 }
2491
2492 /**
2493 * @ingroup mdns
2494 * Checks if an MDNS responder is active for a given network interface.
2495 * @param netif The network interface to test.
2496 * @return nonzero if responder active, zero otherwise.
2497 */
2498 int
mdns_resp_netif_active(struct netif * netif)2499 mdns_resp_netif_active(struct netif *netif)
2500 {
2501 return NETIF_TO_HOST(netif) != NULL;
2502 }
2503
2504 /**
2505 * @ingroup mdns
2506 * Add a service to the selected network interface.
2507 * @param netif The network interface to publish this service on
2508 * @param name The name of the service
2509 * @param service The service type, like "_http"
2510 * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP
2511 * for others ("_udp")
2512 * @param port The port the service listens to
2513 * @param txt_fn Callback to get TXT data. Will be called each time a TXT reply is created to
2514 * allow dynamic replies.
2515 * @param txt_data Userdata pointer for txt_fn
2516 * @return service_id if the service was added to the netif, an err_t otherwise
2517 */
2518 s8_t
mdns_resp_add_service(struct netif * netif,const char * name,const char * service,enum mdns_sd_proto proto,u16_t port,service_get_txt_fn_t txt_fn,void * txt_data)2519 mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_data)
2520 {
2521 u8_t slot;
2522 struct mdns_service *srv;
2523 struct mdns_host *mdns;
2524
2525 LWIP_ASSERT_CORE_LOCKED();
2526 LWIP_ASSERT("mdns_resp_add_service: netif != NULL", netif);
2527 mdns = NETIF_TO_HOST(netif);
2528 LWIP_ERROR("mdns_resp_add_service: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2529
2530 LWIP_ERROR("mdns_resp_add_service: Name too long", (strlen(name) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2531 LWIP_ERROR("mdns_resp_add_service: Service too long", (strlen(service) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2532 LWIP_ERROR("mdns_resp_add_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL);
2533
2534 for (slot = 0; slot < MDNS_MAX_SERVICES; slot++) {
2535 if (mdns->services[slot] == NULL) {
2536 break;
2537 }
2538 }
2539 LWIP_ERROR("mdns_resp_add_service: Service list full (increase MDNS_MAX_SERVICES)", (slot < MDNS_MAX_SERVICES), return ERR_MEM);
2540
2541 srv = (struct mdns_service *)mem_calloc(1, sizeof(struct mdns_service));
2542 LWIP_ERROR("mdns_resp_add_service: Alloc failed", (srv != NULL), return ERR_MEM);
2543
2544 MEMCPY(&srv->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(name)));
2545 MEMCPY(&srv->service, service, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(service)));
2546 srv->txt_fn = txt_fn;
2547 srv->txt_userdata = txt_data;
2548 srv->proto = (u16_t)proto;
2549 srv->port = port;
2550
2551 mdns->services[slot] = srv;
2552
2553 mdns_resp_restart(netif);
2554
2555 return slot;
2556 }
2557
2558 /**
2559 * @ingroup mdns
2560 * Delete a service on the selected network interface.
2561 * @param netif The network interface on which service should be removed
2562 * @param slot The service slot number returned by mdns_resp_add_service
2563 * @return ERR_OK if the service was removed from the netif, an err_t otherwise
2564 */
2565 err_t
mdns_resp_del_service(struct netif * netif,u8_t slot)2566 mdns_resp_del_service(struct netif *netif, u8_t slot)
2567 {
2568 struct mdns_host *mdns;
2569 struct mdns_service *srv;
2570 LWIP_ASSERT("mdns_resp_del_service: netif != NULL", netif);
2571 mdns = NETIF_TO_HOST(netif);
2572 LWIP_ERROR("mdns_resp_del_service: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2573 LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", slot < MDNS_MAX_SERVICES, return ERR_VAL);
2574 LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL);
2575
2576 srv = mdns->services[slot];
2577 mdns->services[slot] = NULL;
2578 mem_free(srv);
2579 return ERR_OK;
2580 }
2581
2582 /**
2583 * @ingroup mdns
2584 * Update name for an MDNS service.
2585 * @param netif The network interface to activate.
2586 * @param slot The service slot number returned by mdns_resp_add_service
2587 * @param name The new name for the service
2588 * @return ERR_OK if name could be set on service, an err_t otherwise
2589 */
2590 err_t
mdns_resp_rename_service(struct netif * netif,u8_t slot,const char * name)2591 mdns_resp_rename_service(struct netif *netif, u8_t slot, const char *name)
2592 {
2593 struct mdns_service *srv;
2594 struct mdns_host *mdns;
2595 size_t len;
2596
2597 LWIP_ASSERT_CORE_LOCKED();
2598 len = strlen(name);
2599 LWIP_ASSERT("mdns_resp_rename_service: netif != NULL", netif);
2600 mdns = NETIF_TO_HOST(netif);
2601 LWIP_ERROR("mdns_resp_rename_service: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2602 LWIP_ERROR("mdns_resp_rename_service: Name too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2603 LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", slot < MDNS_MAX_SERVICES, return ERR_VAL);
2604 LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL);
2605
2606 srv = mdns->services[slot];
2607
2608 MEMCPY(&srv->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, len));
2609 srv->name[len] = '\0'; /* null termination in case new name is shorter than previous */
2610
2611 mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS);
2612
2613 return ERR_OK;
2614 }
2615
2616 /**
2617 * @ingroup mdns
2618 * Call this function from inside the service_get_txt_fn_t callback to add text data.
2619 * Buffer for TXT data is 256 bytes, and each field is prefixed with a length byte.
2620 * @param service The service provided to the get_txt callback
2621 * @param txt String to add to the TXT field.
2622 * @param txt_len Length of string
2623 * @return ERR_OK if the string was added to the reply, an err_t otherwise
2624 */
2625 err_t
mdns_resp_add_service_txtitem(struct mdns_service * service,const char * txt,u8_t txt_len)2626 mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len)
2627 {
2628 LWIP_ASSERT_CORE_LOCKED();
2629 LWIP_ASSERT("mdns_resp_add_service_txtitem: service != NULL", service);
2630
2631 /* Use a mdns_domain struct to store txt chunks since it is the same encoding */
2632 return mdns_domain_add_label(&service->txtdata, txt, txt_len);
2633 }
2634
2635 #if LWIP_MDNS_SEARCH
2636 /**
2637 * @ingroup mdns
2638 * Stop a search request.
2639 * @param request_id The search request to stop
2640 */
2641 void
mdns_search_stop(u8_t request_id)2642 mdns_search_stop(u8_t request_id)
2643 {
2644 struct mdns_request *req;
2645 LWIP_ASSERT("mdns_search_stop: bad request_id", request_id < MDNS_MAX_REQUESTS);
2646 req = &mdns_requests[request_id];
2647 if (req && req->result_fn) {
2648 req->result_fn = NULL;
2649 }
2650 }
2651
2652 /**
2653 * @ingroup mdns
2654 * Search a specific service on the network.
2655 * @param name The name of the service
2656 * @param service The service type, like "_http"
2657 * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP
2658 * for others ("_udp")
2659 * @param netif The network interface where to send search request
2660 * @param result_fn Callback to send answer received. Will be called for each answer of a
2661 * response frame matching request sent.
2662 * @param arg Userdata pointer for result_fn
2663 * @param request_id Returned request identifier to allow stop it.
2664 * @return ERR_OK if the search request was created and sent, an err_t otherwise
2665 */
2666 err_t
mdns_search_service(const char * name,const char * service,enum mdns_sd_proto proto,struct netif * netif,search_result_fn_t result_fn,void * arg,u8_t * request_id)2667 mdns_search_service(const char *name, const char *service, enum mdns_sd_proto proto,
2668 struct netif *netif, search_result_fn_t result_fn, void *arg,
2669 u8_t *request_id)
2670 {
2671 u8_t slot;
2672 struct mdns_request *req;
2673 if (name) {
2674 LWIP_ERROR("mdns_search_service: Name too long", (strlen(name) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2675 }
2676 LWIP_ERROR("mdns_search_service: Service too long", (strlen(service) < MDNS_DOMAIN_MAXLEN), return ERR_VAL);
2677 LWIP_ERROR("mdns_search_service: Bad reqid pointer", request_id, return ERR_VAL);
2678 LWIP_ERROR("mdns_search_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL);
2679 for (slot = 0; slot < MDNS_MAX_REQUESTS; slot++) {
2680 if (mdns_requests[slot].result_fn == NULL) {
2681 break;
2682 }
2683 }
2684 if (slot >= MDNS_MAX_REQUESTS) {
2685 /* Don't assert if no more space in mdns_request table. Just return an error. */
2686 return ERR_MEM;
2687 }
2688
2689 req = &mdns_requests[slot];
2690 memset(req, 0, sizeof(struct mdns_request));
2691 req->result_fn = result_fn;
2692 req->arg = arg;
2693 req->proto = (u16_t)proto;
2694 req->qtype = DNS_RRTYPE_PTR;
2695 if (proto == DNSSD_PROTO_UDP && strcmp(service, "_services._dns-sd") == 0) {
2696 req->only_ptr = 1; /* don't check other answers */
2697 }
2698 mdns_domain_add_string(&req->service, service);
2699 if (name) {
2700 MEMCPY(&req->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(name)));
2701 }
2702 /* save request id (slot) in pointer provided by caller */
2703 *request_id = slot;
2704 /* now prepare a MDNS request and send it (on specified interface) */
2705 #if LWIP_IPV6
2706 mdns_send_request(req, netif, &v6group);
2707 #endif
2708 #if LWIP_IPV4
2709 mdns_send_request(req, netif, &v4group);
2710 #endif
2711 return ERR_OK;
2712 }
2713 #endif
2714
2715 /**
2716 * @ingroup mdns
2717 * Send unsolicited answer containing all our known data
2718 * @param netif The network interface to send on
2719 */
2720 void
mdns_resp_announce(struct netif * netif)2721 mdns_resp_announce(struct netif *netif)
2722 {
2723 struct mdns_host* mdns;
2724 LWIP_ASSERT_CORE_LOCKED();
2725 LWIP_ERROR("mdns_resp_announce: netif != NULL", (netif != NULL), return);
2726
2727 mdns = NETIF_TO_HOST(netif);
2728 if (mdns == NULL) {
2729 return;
2730 }
2731
2732 /* Do not announce if the mdns responder is off, waiting to probe, probing or
2733 * waiting to announce. */
2734 if (mdns->state >= MDNS_STATE_ANNOUNCING) {
2735 /* Announce on IPv6 and IPv4 */
2736 #if LWIP_IPV6
2737 mdns_announce(netif, &v6group);
2738 mdns_start_multicast_timeouts_ipv6(netif);
2739 #endif
2740 #if LWIP_IPV4
2741 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
2742 mdns_announce(netif, &v4group);
2743 mdns_start_multicast_timeouts_ipv4(netif);
2744 }
2745 #endif
2746 } /* else: ip address changed while probing was ongoing? @todo reset counter to restart? */
2747 }
2748
2749 /** Register a callback function that is called if probing is completed successfully
2750 * or with a conflict. */
2751 void
mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb)2752 mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb)
2753 {
2754 mdns_name_result_cb = cb;
2755 }
2756
2757 /**
2758 * @ingroup mdns
2759 * Restart mdns responder after a specified delay. Call this when cable is connected
2760 * after being disconnected or administrative interface is set up after being down
2761 * @param netif The network interface to send on
2762 * @param delay The delay to use before sending probe
2763 */
2764 void
mdns_resp_restart_delay(struct netif * netif,uint32_t delay)2765 mdns_resp_restart_delay(struct netif *netif, uint32_t delay)
2766 {
2767 struct mdns_host* mdns;
2768 LWIP_ASSERT_CORE_LOCKED();
2769 LWIP_ERROR("mdns_resp_restart: netif != NULL", (netif != NULL), return);
2770
2771 mdns = NETIF_TO_HOST(netif);
2772 if (mdns == NULL) {
2773 return;
2774 }
2775 /* Make sure timer is not running */
2776 sys_untimeout(mdns_probe_and_announce, netif);
2777
2778 mdns->sent_num = 0;
2779 mdns->state = MDNS_STATE_PROBE_WAIT;
2780
2781 /* RFC6762 section 8.1: If fifteen conflicts occur within any ten-second period,
2782 * then the host MUST wait at least five seconds before each successive
2783 * additional probe attempt.
2784 */
2785 if (mdns->rate_limit_activated == 1) {
2786 sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif);
2787 }
2788 else {
2789 /* Adjust probe delay according sent probe count. */
2790 sys_timeout(delay, mdns_probe_and_announce, netif);
2791 }
2792 }
2793
2794 /**
2795 * @ingroup mdns
2796 * Restart mdns responder. Call this when cable is connected after being disconnected or
2797 * administrative interface is set up after being down
2798 * @param netif The network interface to send on
2799 */
2800 void
mdns_resp_restart(struct netif * netif)2801 mdns_resp_restart(struct netif *netif)
2802 {
2803 mdns_resp_restart_delay(netif, MDNS_INITIAL_PROBE_DELAY_MS);
2804 }
2805
2806 /**
2807 * @ingroup mdns
2808 * Initiate MDNS responder. Will open UDP sockets on port 5353
2809 */
2810 void
mdns_resp_init(void)2811 mdns_resp_init(void)
2812 {
2813 err_t res;
2814
2815 /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
2816 #if LWIP_MDNS_SEARCH
2817 memset(mdns_requests, 0, sizeof(mdns_requests));
2818 #endif
2819 LWIP_MEMPOOL_INIT(MDNS_PKTS);
2820 mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
2821 LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL);
2822 #if LWIP_MULTICAST_TX_OPTIONS
2823 udp_set_multicast_ttl(mdns_pcb, MDNS_IP_TTL);
2824 #else
2825 mdns_pcb->ttl = MDNS_IP_TTL;
2826 #endif
2827 res = udp_bind(mdns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_MDNS);
2828 LWIP_UNUSED_ARG(res); /* in case of LWIP_NOASSERT */
2829 LWIP_ASSERT("Failed to bind pcb", res == ERR_OK);
2830 udp_recv(mdns_pcb, mdns_recv, NULL);
2831
2832 mdns_netif_client_id = netif_alloc_client_data_id();
2833
2834 #if MDNS_RESP_USENETIF_EXTCALLBACK
2835 /* register for netif events when started on first netif */
2836 netif_add_ext_callback(&netif_callback, mdns_netif_ext_status_callback);
2837 #endif
2838 }
2839
2840 /**
2841 * @ingroup mdns
2842 * Return TXT userdata of a specific service on a network interface.
2843 * @param netif Network interface.
2844 * @param slot Service index.
2845 */
mdns_get_service_txt_userdata(struct netif * netif,s8_t slot)2846 void *mdns_get_service_txt_userdata(struct netif *netif, s8_t slot)
2847 {
2848 struct mdns_host *mdns = NETIF_TO_HOST(netif);
2849 struct mdns_service *s;
2850 LWIP_ASSERT("mdns_get_service_txt_userdata: index out of range", slot < MDNS_MAX_SERVICES);
2851 s = mdns->services[slot];
2852 return s ? s->txt_userdata : NULL;
2853 }
2854
2855 #endif /* LWIP_MDNS_RESPONDER */
2856