1 /**
2 * @file
3 * MDNS responder implementation - domain related functionalities
4 */
5
6 /*
7 * Copyright (c) 2015 Verisure Innovation AB
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 *
32 * This file is part of the lwIP TCP/IP stack.
33 *
34 * Author: Erik Ekman <erik@kryo.se>
35 * Author: Jasper Verschueren <jasper.verschueren@apart-audio.com>
36 *
37 */
38
39 #include "lwip/apps/mdns.h"
40 #include "lwip/apps/mdns_domain.h"
41 #include "lwip/apps/mdns_priv.h"
42 #include "lwip/prot/dns.h"
43
44 #include <string.h>
45
46 #if LWIP_IPV6
47 #include "lwip/prot/ip6.h"
48 #endif
49
50 #if LWIP_MDNS_RESPONDER
51
52 /* Stored offsets to beginning of domain names
53 * Used for compression.
54 */
55 #define DOMAIN_JUMP_SIZE 2
56 #define DOMAIN_JUMP 0xc000
57
58 #define TOPDOMAIN_LOCAL "local"
59
60 #define REVERSE_PTR_TOPDOMAIN "arpa"
61 #define REVERSE_PTR_V4_DOMAIN "in-addr"
62 #define REVERSE_PTR_V6_DOMAIN "ip6"
63
64 static const char *dnssd_protos[] = {
65 "_udp", /* DNSSD_PROTO_UDP */
66 "_tcp", /* DNSSD_PROTO_TCP */
67 };
68
69 /* forward declarations (function prototypes)*/
70 static err_t mdns_domain_add_label_base(struct mdns_domain *domain, u8_t len);
71 static err_t mdns_domain_add_label_pbuf(struct mdns_domain *domain,
72 const struct pbuf *p, u16_t offset,
73 u8_t len);
74 static u16_t mdns_readname_loop(struct pbuf *p, u16_t offset,
75 struct mdns_domain *domain, unsigned depth);
76 static err_t mdns_add_dotlocal(struct mdns_domain *domain);
77
78
79 static err_t
mdns_domain_add_label_base(struct mdns_domain * domain,u8_t len)80 mdns_domain_add_label_base(struct mdns_domain *domain, u8_t len)
81 {
82 if (len > MDNS_LABEL_MAXLEN) {
83 return ERR_VAL;
84 }
85 if (len > 0 && (1 + len + domain->length >= MDNS_DOMAIN_MAXLEN)) {
86 return ERR_VAL;
87 }
88 /* Allow only zero marker on last byte */
89 if (len == 0 && (1 + domain->length > MDNS_DOMAIN_MAXLEN)) {
90 return ERR_VAL;
91 }
92 domain->name[domain->length] = len;
93 domain->length++;
94 return ERR_OK;
95 }
96
97 /**
98 * Add a label part to a domain
99 * @param domain The domain to add a label to
100 * @param label The label to add, like <hostname>, 'local', 'com' or ''
101 * @param len The length of the label
102 * @return ERR_OK on success, an err_t otherwise if label too long
103 */
104 err_t
mdns_domain_add_label(struct mdns_domain * domain,const char * label,u8_t len)105 mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len)
106 {
107 err_t err = mdns_domain_add_label_base(domain, len);
108 if (err != ERR_OK) {
109 return err;
110 }
111 if (len) {
112 MEMCPY(&domain->name[domain->length], label, len);
113 domain->length += len;
114 }
115 return ERR_OK;
116 }
117
118 /**
119 * Add a label part to a domain (@see mdns_domain_add_label but copy directly from pbuf)
120 */
121 static err_t
mdns_domain_add_label_pbuf(struct mdns_domain * domain,const struct pbuf * p,u16_t offset,u8_t len)122 mdns_domain_add_label_pbuf(struct mdns_domain *domain, const struct pbuf *p, u16_t offset, u8_t len)
123 {
124 err_t err = mdns_domain_add_label_base(domain, len);
125 if (err != ERR_OK) {
126 return err;
127 }
128 if (len) {
129 if (pbuf_copy_partial(p, &domain->name[domain->length], len, offset) != len) {
130 /* take back the ++ done before */
131 domain->length--;
132 return ERR_ARG;
133 }
134 domain->length += len;
135 }
136 return ERR_OK;
137 }
138
139 /**
140 * Add a partial domain to a domain
141 * @param domain The domain to add a label to
142 * @param source The domain to add, like <\\x09_services\\007_dns-sd\\000>
143 * @return ERR_OK on success, an err_t otherwise if label too long
144 */
145 err_t
mdns_domain_add_domain(struct mdns_domain * domain,struct mdns_domain * source)146 mdns_domain_add_domain(struct mdns_domain *domain, struct mdns_domain *source)
147 {
148 u16_t len = source->length;
149 if (len > 0 && (1 + len + domain->length >= MDNS_DOMAIN_MAXLEN)) {
150 return ERR_VAL;
151 }
152 /* Allow only zero marker on last byte */
153 if (len == 0 && (1 + domain->length > MDNS_DOMAIN_MAXLEN)) {
154 return ERR_VAL;
155 }
156 if (len) {
157 /* Copy partial domain */
158 MEMCPY(&domain->name[domain->length], source->name, len);
159 domain->length += len;
160 } else {
161 /* Add zero marker */
162 domain->name[domain->length] = 0;
163 domain->length++;
164 }
165 return ERR_OK;
166 }
167
168 /**
169 * Add a string domain to a domain
170 * @param domain The domain to add a label to
171 * @param source The string to add, like <_services._dns-sd>
172 * @return ERR_OK on success, an err_t otherwise if label too long
173 */
174 err_t
mdns_domain_add_string(struct mdns_domain * domain,const char * source)175 mdns_domain_add_string(struct mdns_domain *domain, const char *source)
176 {
177 u8_t *len = &domain->name[domain->length];
178 u8_t *end = &domain->name[MDNS_DOMAIN_MAXLEN];
179 u8_t *start = len + 1;
180 *len = 0;
181 while (*source && start < end) {
182 if (*source == '.') {
183 len = start++;
184 *len = 0;
185 source++;
186 } else {
187 *start++ = *source++;
188 *len = *len + 1;
189 }
190 }
191 if (start == end) {
192 return ERR_VAL;
193 }
194 domain->length = (u16_t)(start - &domain->name[0]);
195 return ERR_OK;
196 }
197
198
199 /**
200 * Internal readname function with max 6 levels of recursion following jumps
201 * while decompressing name
202 */
203 static u16_t
mdns_readname_loop(struct pbuf * p,u16_t offset,struct mdns_domain * domain,unsigned depth)204 mdns_readname_loop(struct pbuf *p, u16_t offset, struct mdns_domain *domain, unsigned depth)
205 {
206 u8_t c;
207
208 do {
209 if (depth > 5) {
210 /* Too many jumps */
211 return MDNS_READNAME_ERROR;
212 }
213
214 c = pbuf_get_at(p, offset);
215 offset++;
216
217 /* is this a compressed label? */
218 if ((c & 0xc0) == 0xc0) {
219 u16_t jumpaddr;
220 if (offset >= p->tot_len) {
221 /* Make sure both jump bytes fit in the packet */
222 return MDNS_READNAME_ERROR;
223 }
224 jumpaddr = (((c & 0x3f) << 8) | (pbuf_get_at(p, offset) & 0xff));
225 offset++;
226 if (jumpaddr >= SIZEOF_DNS_HDR && jumpaddr < p->tot_len) {
227 u16_t res;
228 /* Recursive call, maximum depth will be checked */
229 res = mdns_readname_loop(p, jumpaddr, domain, depth + 1);
230 /* Don't return offset since new bytes were not read (jumped to somewhere in packet) */
231 if (res == MDNS_READNAME_ERROR) {
232 return res;
233 }
234 } else {
235 return MDNS_READNAME_ERROR;
236 }
237 break;
238 }
239
240 /* normal label */
241 if (c <= MDNS_LABEL_MAXLEN) {
242 err_t res;
243
244 if (c + domain->length >= MDNS_DOMAIN_MAXLEN) {
245 return MDNS_READNAME_ERROR;
246 }
247 res = mdns_domain_add_label_pbuf(domain, p, offset, c);
248 if (res != ERR_OK) {
249 return MDNS_READNAME_ERROR;
250 }
251 offset += c;
252 } else {
253 /* bad length byte */
254 return MDNS_READNAME_ERROR;
255 }
256 } while (c != 0);
257
258 return offset;
259 }
260
261 /**
262 * Read possibly compressed domain name from packet buffer
263 * @param p The packet
264 * @param offset start position of domain name in packet
265 * @param domain The domain name destination
266 * @return The new offset after the domain, or MDNS_READNAME_ERROR
267 * if reading failed
268 */
269 u16_t
mdns_readname(struct pbuf * p,u16_t offset,struct mdns_domain * domain)270 mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain)
271 {
272 memset(domain, 0, sizeof(struct mdns_domain));
273 return mdns_readname_loop(p, offset, domain, 0);
274 }
275
276 /**
277 * Print domain name to debug output
278 * @param domain The domain name
279 */
280 void
mdns_domain_debug_print(struct mdns_domain * domain)281 mdns_domain_debug_print(struct mdns_domain *domain)
282 {
283 u8_t *src = domain->name;
284 u8_t i;
285
286 while (*src) {
287 u8_t label_len = *src;
288 src++;
289 for (i = 0; i < label_len; i++) {
290 LWIP_DEBUGF(MDNS_DEBUG, ("%c", src[i]));
291 }
292 src += label_len;
293 LWIP_DEBUGF(MDNS_DEBUG, ("."));
294 }
295 }
296
297 /**
298 * Return 1 if contents of domains match (case-insensitive)
299 * @param a Domain name to compare 1
300 * @param b Domain name to compare 2
301 * @return 1 if domains are equal ignoring case, 0 otherwise
302 */
303 int
mdns_domain_eq(struct mdns_domain * a,struct mdns_domain * b)304 mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b)
305 {
306 u8_t *ptra, *ptrb;
307 u8_t len;
308 int res;
309
310 if (a->length != b->length) {
311 return 0;
312 }
313
314 ptra = a->name;
315 ptrb = b->name;
316 while (*ptra && *ptrb && ptra < &a->name[a->length]) {
317 if (*ptra != *ptrb) {
318 return 0;
319 }
320 len = *ptra;
321 ptra++;
322 ptrb++;
323 res = lwip_strnicmp((char *) ptra, (char *) ptrb, len);
324 if (res != 0) {
325 return 0;
326 }
327 ptra += len;
328 ptrb += len;
329 }
330 if (*ptra != *ptrb && ptra < &a->name[a->length]) {
331 return 0;
332 }
333 return 1;
334 }
335
336 #if LWIP_IPV4
337 /**
338 * Build domain for reverse lookup of IPv4 address
339 * like 12.0.168.192.in-addr.arpa. for 192.168.0.12
340 * @param domain Where to write the domain name
341 * @param addr Pointer to an IPv4 address to encode
342 * @return ERR_OK if domain was written, an err_t otherwise
343 */
344 err_t
mdns_build_reverse_v4_domain(struct mdns_domain * domain,const ip4_addr_t * addr)345 mdns_build_reverse_v4_domain(struct mdns_domain *domain, const ip4_addr_t *addr)
346 {
347 int i;
348 err_t res;
349 const u8_t *ptr;
350
351 LWIP_UNUSED_ARG(res);
352 if (!domain || !addr) {
353 return ERR_ARG;
354 }
355 memset(domain, 0, sizeof(struct mdns_domain));
356 ptr = (const u8_t *) addr;
357 for (i = sizeof(ip4_addr_t) - 1; i >= 0; i--) {
358 char buf[4];
359 u8_t val = ptr[i];
360
361 lwip_itoa(buf, sizeof(buf), val);
362 res = mdns_domain_add_label(domain, buf, (u8_t)strlen(buf));
363 LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res);
364 }
365 res = mdns_domain_add_label(domain, REVERSE_PTR_V4_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V4_DOMAIN) - 1));
366 LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res);
367 res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN) - 1));
368 LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res);
369 res = mdns_domain_add_label(domain, NULL, 0);
370 LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res);
371
372 return ERR_OK;
373 }
374 #endif
375
376 #if LWIP_IPV6
377 /**
378 * Build domain for reverse lookup of IP address
379 * like b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. for 2001:db8::567:89ab
380 * @param domain Where to write the domain name
381 * @param addr Pointer to an IPv6 address to encode
382 * @return ERR_OK if domain was written, an err_t otherwise
383 */
384 err_t
mdns_build_reverse_v6_domain(struct mdns_domain * domain,const ip6_addr_t * addr)385 mdns_build_reverse_v6_domain(struct mdns_domain *domain, const ip6_addr_t *addr)
386 {
387 int i;
388 err_t res;
389 const u8_t *ptr;
390 LWIP_UNUSED_ARG(res);
391 if (!domain || !addr) {
392 return ERR_ARG;
393 }
394 memset(domain, 0, sizeof(struct mdns_domain));
395 ptr = (const u8_t *) addr;
396 for (i = sizeof(ip6_addr_p_t) - 1; i >= 0; i--) {
397 char buf;
398 u8_t byte = ptr[i];
399 int j;
400 for (j = 0; j < 2; j++) {
401 if ((byte & 0x0F) < 0xA) {
402 buf = '0' + (byte & 0x0F);
403 } else {
404 buf = 'a' + (byte & 0x0F) - 0xA;
405 }
406 res = mdns_domain_add_label(domain, &buf, sizeof(buf));
407 LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res);
408 byte >>= 4;
409 }
410 }
411 res = mdns_domain_add_label(domain, REVERSE_PTR_V6_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V6_DOMAIN) - 1));
412 LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res);
413 res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN) - 1));
414 LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res);
415 res = mdns_domain_add_label(domain, NULL, 0);
416 LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res);
417
418 return ERR_OK;
419 }
420 #endif
421
422 /* Add .local. to domain */
423 static err_t
mdns_add_dotlocal(struct mdns_domain * domain)424 mdns_add_dotlocal(struct mdns_domain *domain)
425 {
426 err_t res = mdns_domain_add_label(domain, TOPDOMAIN_LOCAL, (u8_t)(sizeof(TOPDOMAIN_LOCAL) - 1));
427 LWIP_UNUSED_ARG(res);
428 LWIP_ERROR("mdns_add_dotlocal: Failed to add label", (res == ERR_OK), return res);
429 return mdns_domain_add_label(domain, NULL, 0);
430 }
431
432 /**
433 * Build the \<hostname\>.local. domain name
434 * @param domain Where to write the domain name
435 * @param mdns TMDNS netif descriptor.
436 * @return ERR_OK if domain \<hostname\>.local. was written, an err_t otherwise
437 */
438 err_t
mdns_build_host_domain(struct mdns_domain * domain,struct mdns_host * mdns)439 mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns)
440 {
441 err_t res;
442 LWIP_UNUSED_ARG(res);
443 memset(domain, 0, sizeof(struct mdns_domain));
444 LWIP_ERROR("mdns_build_host_domain: mdns != NULL", (mdns != NULL), return ERR_VAL);
445 res = mdns_domain_add_label(domain, mdns->name, (u8_t)strlen(mdns->name));
446 LWIP_ERROR("mdns_build_host_domain: Failed to add label", (res == ERR_OK), return res);
447 return mdns_add_dotlocal(domain);
448 }
449
450 /**
451 * Build the lookup-all-services special DNS-SD domain name
452 * @param domain Where to write the domain name
453 * @return ERR_OK if domain _services._dns-sd._udp.local. was written, an err_t otherwise
454 */
455 err_t
mdns_build_dnssd_domain(struct mdns_domain * domain)456 mdns_build_dnssd_domain(struct mdns_domain *domain)
457 {
458 err_t res;
459 LWIP_UNUSED_ARG(res);
460 memset(domain, 0, sizeof(struct mdns_domain));
461 res = mdns_domain_add_label(domain, "_services", (u8_t)(sizeof("_services") - 1));
462 LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res);
463 res = mdns_domain_add_label(domain, "_dns-sd", (u8_t)(sizeof("_dns-sd") - 1));
464 LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res);
465 res = mdns_domain_add_label(domain, dnssd_protos[DNSSD_PROTO_UDP], (u8_t)strlen(dnssd_protos[DNSSD_PROTO_UDP]));
466 LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res);
467 return mdns_add_dotlocal(domain);
468 }
469
470 /**
471 * Build domain name for a service
472 * @param domain Where to write the domain name
473 * @param service The service struct, containing service name, type and protocol
474 * @param include_name Whether to include the service name in the domain
475 * @return ERR_OK if domain was written. If service name is included,
476 * \<name\>.\<type\>.\<proto\>.local. will be written, otherwise \<type\>.\<proto\>.local.
477 * An err_t is returned on error.
478 */
479 err_t
mdns_build_service_domain(struct mdns_domain * domain,struct mdns_service * service,int include_name)480 mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *service, int include_name)
481 {
482 err_t res;
483 LWIP_UNUSED_ARG(res);
484 memset(domain, 0, sizeof(struct mdns_domain));
485 if (include_name) {
486 res = mdns_domain_add_label(domain, service->name, (u8_t)strlen(service->name));
487 LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res);
488 }
489 res = mdns_domain_add_label(domain, service->service, (u8_t)strlen(service->service));
490 LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res);
491 res = mdns_domain_add_label(domain, dnssd_protos[service->proto], (u8_t)strlen(dnssd_protos[service->proto]));
492 LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res);
493 return mdns_add_dotlocal(domain);
494 }
495
496 #if LWIP_MDNS_SEARCH
497 /**
498 * Build domain name for a request
499 * @param domain Where to write the domain name
500 * @param request The request struct, containing service name, type and protocol
501 * @param include_name Whether to include the service name in the domain
502 * @return ERR_OK if domain was written. If service name is included,
503 * \<name\>.\<type\>.\<proto\>.local. will be written, otherwise \<type\>.\<proto\>.local.
504 * An err_t is returned on error.
505 */
506 err_t
mdns_build_request_domain(struct mdns_domain * domain,struct mdns_request * request,int include_name)507 mdns_build_request_domain(struct mdns_domain *domain, struct mdns_request *request, int include_name)
508 {
509 err_t res;
510 memset(domain, 0, sizeof(struct mdns_domain));
511 if (include_name) {
512 res = mdns_domain_add_label(domain, request->name, (u8_t)strlen(request->name));
513 LWIP_ERROR("mdns_build_request_domain: Failed to add label", (res == ERR_OK), return res);
514 }
515 res = mdns_domain_add_domain(domain, &request->service);
516 LWIP_ERROR("mdns_build_request_domain: Failed to add domain", (res == ERR_OK), return res);
517 res = mdns_domain_add_label(domain, dnssd_protos[request->proto], (u8_t)strlen(dnssd_protos[request->proto]));
518 LWIP_ERROR("mdns_build_request_domain: Failed to add label", (res == ERR_OK), return res);
519 return mdns_add_dotlocal(domain);
520 }
521 #endif
522
523 /**
524 * Return bytes needed to write before jump for best result of compressing supplied domain
525 * against domain in outpacket starting at specified offset.
526 * If a match is found, offset is updated to where to jump to
527 * @param pbuf Pointer to pbuf with the partially constructed DNS packet
528 * @param offset Start position of a domain written earlier. If this location is suitable
529 * for compression, the pointer is updated to where in the domain to jump to.
530 * @param domain The domain to write
531 * @return Number of bytes to write of the new domain before writing a jump to the offset.
532 * If compression can not be done against this previous domain name, the full new
533 * domain length is returned.
534 */
535 u16_t
mdns_compress_domain(struct pbuf * pbuf,u16_t * offset,struct mdns_domain * domain)536 mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain)
537 {
538 struct mdns_domain target;
539 u16_t target_end;
540 u8_t target_len;
541 u8_t writelen = 0;
542 u8_t *ptr;
543 if (pbuf == NULL) {
544 return domain->length;
545 }
546 target_end = mdns_readname(pbuf, *offset, &target);
547 if (target_end == MDNS_READNAME_ERROR) {
548 return domain->length;
549 }
550 target_len = (u8_t)(target_end - *offset);
551 ptr = domain->name;
552 while (writelen < domain->length) {
553 u8_t domainlen = (u8_t)(domain->length - writelen);
554 u8_t labellen;
555 if (domainlen <= target.length && domainlen > DOMAIN_JUMP_SIZE) {
556 /* Compare domains if target is long enough, and we have enough left of the domain */
557 u8_t targetpos = (u8_t)(target.length - domainlen);
558 if ((targetpos + DOMAIN_JUMP_SIZE) >= target_len) {
559 /* We are checking at or beyond a jump in the original, stop looking */
560 break;
561 }
562 if (target.length >= domainlen &&
563 memcmp(&domain->name[writelen], &target.name[targetpos], domainlen) == 0) {
564 *offset += targetpos;
565 return writelen;
566 }
567 }
568 /* Skip to next label in domain */
569 labellen = *ptr;
570 writelen += 1 + labellen;
571 ptr += 1 + labellen;
572 }
573 /* Nothing found */
574 return domain->length;
575 }
576
577 /**
578 * Write domain to outpacket. Compression will be attempted,
579 * unless domain->skip_compression is set.
580 * @param outpkt The outpacket to write to
581 * @param domain The domain name to write
582 * @return ERR_OK on success, an err_t otherwise
583 */
584 err_t
mdns_write_domain(struct mdns_outpacket * outpkt,struct mdns_domain * domain)585 mdns_write_domain(struct mdns_outpacket *outpkt, struct mdns_domain *domain)
586 {
587 int i;
588 err_t res;
589 u16_t writelen = domain->length;
590 u16_t jump_offset = 0;
591 u16_t jump;
592
593 if (!domain->skip_compression) {
594 for (i = 0; i < NUM_DOMAIN_OFFSETS; i++) {
595 u16_t offset = outpkt->domain_offsets[i];
596 if (offset) {
597 u16_t len = mdns_compress_domain(outpkt->pbuf, &offset, domain);
598 if (len < writelen) {
599 writelen = len;
600 jump_offset = offset;
601 }
602 }
603 }
604 }
605
606 if (writelen) {
607 /* Write uncompressed part of name */
608 res = pbuf_take_at(outpkt->pbuf, domain->name, writelen, outpkt->write_offset);
609 if (res != ERR_OK) {
610 return res;
611 }
612
613 /* Store offset of this new domain */
614 for (i = 0; i < NUM_DOMAIN_OFFSETS; i++) {
615 if (outpkt->domain_offsets[i] == 0) {
616 outpkt->domain_offsets[i] = outpkt->write_offset;
617 break;
618 }
619 }
620
621 outpkt->write_offset += writelen;
622 }
623 if (jump_offset) {
624 /* Write jump */
625 jump = lwip_htons(DOMAIN_JUMP | jump_offset);
626 res = pbuf_take_at(outpkt->pbuf, &jump, DOMAIN_JUMP_SIZE, outpkt->write_offset);
627 if (res != ERR_OK) {
628 return res;
629 }
630 outpkt->write_offset += DOMAIN_JUMP_SIZE;
631 }
632 return ERR_OK;
633 }
634
635 #endif /* LWIP_MDNS_RESPONDER */
636