• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/mdnsd/dns.c

  1 /*
  2  * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  */
 13 
 14 #define _GNU_SOURCE
 15 #include <sys/types.h>
 16 #include <sys/stat.h>
 17 
 18 #include <fcntl.h>
 19 #include <ifaddrs.h>
 20 #include <time.h>
 21 #include <stdio.h>
 22 #include <unistd.h>
 23 #include <sys/types.h>
 24 #include <sys/socket.h>
 25 #include <netinet/in.h>
 26 #include <arpa/inet.h>
 27 #include <arpa/nameser.h>
 28 #include <resolv.h>
 29 #include <stdlib.h>
 30 #include <string.h>
 31 
 32 #include <libubox/uloop.h>
 33 #include <libubox/usock.h>
 34 #include <libubox/utils.h>
 35 #include <libubox/avl-cmp.h>
 36 
 37 #include "announce.h"
 38 #include "util.h"
 39 #include "dns.h"
 40 #include "cache.h"
 41 #include "service.h"
 42 #include "interface.h"
 43 
 44 #define QUERY_BATCH_SIZE        16
 45 
 46 struct query_entry {
 47         struct avl_node node;
 48         uint16_t type;
 49         char name[];
 50 };
 51 
 52 static AVL_TREE(queries, avl_strcmp, true, NULL);
 53 static char name_buffer[MAX_NAME_LEN + 1];
 54 
 55 static struct {
 56         struct dns_header h;
 57         unsigned char data[9000 - sizeof(struct dns_header)];
 58 } __attribute__((packed)) pkt;
 59 static size_t pkt_len;
 60 static struct dns_question *pkt_q[32];
 61 static unsigned int pkt_n_q;
 62 static unsigned char *dnptrs[255];
 63 
 64 const char*
 65 dns_type_string(uint16_t type)
 66 {
 67         static const struct {
 68                 uint16_t type;
 69                 char str[5];
 70         } type_str[] = {
 71                 { TYPE_A, "A" },
 72                 { TYPE_AAAA, "AAAA" },
 73                 { TYPE_PTR, "PTR" },
 74                 { TYPE_TXT, "TXT" },
 75                 { TYPE_SRV, "SRV" },
 76                 { TYPE_ANY, "ANY" },
 77         };
 78         int i;
 79 
 80         for (i = 0; i < ARRAY_SIZE(type_str); i++) {
 81                 if (type == type_str[i].type)
 82                         return type_str[i].str;
 83         }
 84 
 85         return "N/A";
 86 }
 87 
 88 void dns_packet_init(void)
 89 {
 90         dnptrs[0] = (unsigned char *)&pkt;
 91         dnptrs[1] = NULL;
 92         pkt_len = 0;
 93         pkt_n_q = 0;
 94         memset(&pkt.h, 0, sizeof(pkt.h));
 95 }
 96 
 97 static inline void *dns_packet_tail(size_t len)
 98 {
 99         if (pkt_len + len > sizeof(pkt.data))
100                 return NULL;
101 
102         return &pkt.data[pkt_len];
103 }
104 
105 static int
106 dns_packet_add_name(const char *name)
107 {
108         void *data;
109 
110         data = dns_packet_tail(MAX_NAME_LEN);
111         if (!data)
112                 return -1;
113 
114         return dn_comp(name, data, MAX_NAME_LEN, dnptrs, dnptrs + ARRAY_SIZE(dnptrs) - 1);
115 }
116 
117 static void *dns_packet_record_add(size_t data_len, const char *name)
118 {
119         void *data;
120         int len;
121 
122         len = dns_packet_add_name(name);
123         if (len < 1)
124                 return NULL;
125 
126         data = dns_packet_tail(len + data_len);
127         if (!data)
128                 return NULL;
129 
130         pkt_len += len + data_len;
131 
132         return data + len;
133 }
134 
135 bool dns_packet_question(const char *name, int type)
136 {
137         struct dns_question *q;
138 
139         q = dns_packet_record_add(sizeof(*q), name);
140         if (!q)
141                 return false;
142 
143         pkt.h.questions += cpu_to_be16(1);
144         pkt_q[pkt_n_q++] = q;
145         memset(q, 0, sizeof(*q));
146         q->class = cpu_to_be16(1);
147         q->type = cpu_to_be16(type);
148         DBG(1, "Q <- %s %s\n", dns_type_string(type), name);
149 
150         return true;
151 }
152 
153 void dns_packet_answer(const char *name, int type, const uint8_t *rdata, uint16_t rdlength, int ttl)
154 {
155         struct dns_answer *a;
156 
157         pkt.h.flags |= cpu_to_be16(0x8400);
158 
159         a = dns_packet_record_add(sizeof(*a) + rdlength, name);
160         memset(a, 0, sizeof(*a));
161         a->type = cpu_to_be16(type);
162         a->class = cpu_to_be16(1);
163         a->ttl = cpu_to_be32(ttl);
164         a->rdlength = cpu_to_be16(rdlength);
165         memcpy(a + 1, rdata, rdlength);
166         DBG(1, "A <- %s %s\n", dns_type_string(be16_to_cpu(a->type)), name);
167 
168         pkt.h.answers += cpu_to_be16(1);
169 }
170 
171 static void dns_question_set_multicast(struct dns_question *q, bool val)
172 {
173         if (val)
174                 q->class &= ~cpu_to_be16(CLASS_UNICAST);
175         else
176                 q->class |= cpu_to_be16(CLASS_UNICAST);
177 }
178 
179 void dns_packet_send(struct interface *iface, struct sockaddr *to, bool query, int multicast)
180 {
181         struct iovec iov = {
182                 .iov_base = &pkt,
183                 .iov_len = sizeof(pkt.h) + pkt_len,
184         };
185         size_t i;
186 
187         if (query) {
188                 if (multicast < 0)
189                         multicast = iface->need_multicast;
190 
191                 for (i = 0; i < pkt_n_q; i++)
192                         dns_question_set_multicast(pkt_q[i], multicast);
193         }
194 
195         if (interface_send_packet(iface, to, &iov, 1) < 0)
196                 perror("failed to send answer");
197 }
198 
199 static void dns_packet_broadcast(void)
200 {
201         struct interface *iface;
202 
203         vlist_for_each_element(&interfaces, iface, node)
204                 dns_packet_send(iface, NULL, 1, -1);
205 }
206 
207 void
208 dns_send_question(struct interface *iface, struct sockaddr *to,
209                   const char *question, int type, int multicast)
210 {
211         dns_packet_init();
212         dns_packet_question(question, type);
213         dns_packet_send(iface, to, true, multicast);
214 }
215 
216 static void
217 dns_query_pending(struct uloop_timeout *t)
218 {
219         struct query_entry *e, *tmp;
220         int count = 0;
221 
222         dns_packet_init();
223         avl_remove_all_elements(&queries, e, node, tmp) {
224                 dns_packet_question(e->name, e->type);
225                 free(e);
226 
227                 if (++count < QUERY_BATCH_SIZE)
228                         continue;
229 
230                 count = 0;
231                 dns_packet_broadcast();
232         }
233 
234         if (count)
235                 dns_packet_broadcast();
236 }
237 
238 void dns_query(const char *name, uint16_t type)
239 {
240         static struct uloop_timeout timer = {
241                 .cb = dns_query_pending
242         };
243         struct query_entry *e;
244 
245         e = avl_find_element(&queries, name, e, node);
246         while (e) {
247                 if (e->type == type)
248                         return;
249 
250                 e = avl_next_element(e, node);
251                 if (strcmp(e->name, name) != 0)
252                         break;
253         }
254 
255         e = calloc(1, sizeof(*e) + strlen(name) + 1);
256         e->type = type;
257         e->node.key = e->name;
258         strcpy(e->name, name);
259         avl_insert(&queries, &e->node);
260 
261         if (queries.count > QUERY_BATCH_SIZE)
262                 timer.cb(&timer);
263 
264         if (!timer.pending)
265                 uloop_timeout_set(&timer, 100);
266 }
267 
268 void
269 dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname)
270 {
271         struct ifaddrs *ifap, *ifa;
272         struct sockaddr_in *sa;
273         struct sockaddr_in6 *sa6;
274 
275         if (!hostname)
276                 hostname = mdns_hostname_local;
277 
278         getifaddrs(&ifap);
279 
280         dns_packet_init();
281         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
282                 if (strcmp(ifa->ifa_name, iface->name))
283                         continue;
284                 if (ifa->ifa_addr->sa_family == AF_INET) {
285                         sa = (struct sockaddr_in *) ifa->ifa_addr;
286                         dns_packet_answer(hostname, TYPE_A, (uint8_t *) &sa->sin_addr, 4, ttl);
287                 }
288                 if (ifa->ifa_addr->sa_family == AF_INET6) {
289                         sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
290                         dns_packet_answer(hostname, TYPE_AAAA, (uint8_t *) &sa6->sin6_addr, 16, ttl);
291                 }
292         }
293         freeifaddrs(ifap);
294 
295         dns_packet_send(iface, to, 0, 0);
296 }
297 
298 void
299 dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl)
300 {
301         struct hostname *h;
302 
303         vlist_for_each_element(&hostnames, h, node)
304                 dns_reply_a(iface, to, ttl, h->hostname);
305 }
306 
307 static int
308 scan_name(const uint8_t *buffer, int len)
309 {
310         int offset = 0;
311 
312         while (len && (*buffer != '\0')) {
313                 int l = *buffer;
314 
315                 if (IS_COMPRESSED(l))
316                         return offset + 2;
317 
318                 if (l + 1 > len) return -1;
319                 len -= l + 1;
320                 offset += l + 1;
321                 buffer += l + 1;
322         }
323 
324         if (!len || !offset || (*buffer != '\0'))
325                 return -1;
326 
327         return offset + 1;
328 }
329 
330 static struct dns_header*
331 dns_consume_header(uint8_t **data, int *len)
332 {
333         struct dns_header *h = (struct dns_header *) *data;
334 
335         if (*len < sizeof(struct dns_header))
336                 return NULL;
337 
338         h->id = be16_to_cpu(h->id);
339         h->flags = be16_to_cpu(h->flags);
340         h->questions = be16_to_cpu(h->questions);
341         h->answers = be16_to_cpu(h->answers);
342         h->authority = be16_to_cpu(h->authority);
343         h->additional = be16_to_cpu(h->additional);
344 
345         *len -= sizeof(struct dns_header);
346         *data += sizeof(struct dns_header);
347 
348         return h;
349 }
350 
351 static struct dns_question*
352 dns_consume_question(uint8_t **data, int *len)
353 {
354         struct dns_question *q = (struct dns_question *) *data;
355 
356         if (*len < sizeof(struct dns_question))
357                 return NULL;
358 
359         q->type = be16_to_cpu(q->type);
360         q->class = be16_to_cpu(q->class);
361 
362         *len -= sizeof(struct dns_question);
363         *data += sizeof(struct dns_question);
364 
365         return q;
366 }
367 
368 static struct dns_answer*
369 dns_consume_answer(uint8_t **data, int *len)
370 {
371         struct dns_answer *a = (struct dns_answer *) *data;
372 
373         if (*len < sizeof(struct dns_answer))
374                 return NULL;
375 
376         a->type = be16_to_cpu(a->type);
377         a->class = be16_to_cpu(a->class);
378         a->ttl = be32_to_cpu(a->ttl);
379         a->rdlength = be16_to_cpu(a->rdlength);
380 
381         *len -= sizeof(struct dns_answer);
382         *data += sizeof(struct dns_answer);
383 
384         return a;
385 }
386 
387 static char *
388 dns_consume_name(const uint8_t *base, int blen, uint8_t **data, int *len)
389 {
390         int nlen = scan_name(*data, *len);
391 
392         if (nlen < 1)
393                 return NULL;
394 
395         if (dn_expand(base, base + blen, *data, name_buffer, MAX_NAME_LEN) < 0) {
396                 perror("dns_consume_name/dn_expand");
397                 return NULL;
398         }
399 
400         *len -= nlen;
401         *data += nlen;
402 
403         return name_buffer;
404 }
405 
406 static int parse_answer(struct interface *iface, struct sockaddr *from,
407                         uint8_t *buffer, int len, uint8_t **b, int *rlen,
408                         int cache)
409 {
410         char *name = dns_consume_name(buffer, len, b, rlen);
411         struct dns_answer *a;
412         uint8_t *rdata;
413 
414         if (!name || *rlen < 0) {
415                 fprintf(stderr, "dropping: bad question\n");
416                 return -1;
417         }
418 
419         a = dns_consume_answer(b, rlen);
420         if (!a) {
421                 fprintf(stderr, "dropping: bad question\n");
422                 return -1;
423         }
424 
425         if ((a->class & ~CLASS_FLUSH) != CLASS_IN)
426                 return -1;
427 
428         rdata = *b;
429         if (a->rdlength > *rlen) {
430                 fprintf(stderr, "dropping: bad question\n");
431                 return -1;
432         }
433 
434         *rlen -= a->rdlength;
435         *b += a->rdlength;
436 
437         if (cache)
438                 cache_answer(iface, from, buffer, len, name, a, rdata, a->class & CLASS_FLUSH);
439 
440         return 0;
441 }
442 
443 static int
444 match_ipv6_addresses(char *reverse_ip, struct in6_addr *intf_ip)
445 {
446         int i = 0, j = 0, idx = 0;
447         char temp_ip[INET6_ADDRSTRLEN] = "";
448         struct in6_addr buf;
449 
450         for (i = strlen(reverse_ip) - 1; i >= 0; i--) {
451                 if (reverse_ip[i] == '.')
452                         continue;
453 
454                 if (j == 4) {
455                         temp_ip[idx] = ':';
456                         idx++;
457                         j = 0;
458                 }
459                 temp_ip[idx] = reverse_ip[i];
460                 idx++;
461                 j++;
462         }
463 
464         if (inet_pton(AF_INET6, temp_ip, &buf) <= 0)
465                 return 0;
466 
467         return !memcmp(&buf, intf_ip, sizeof(buf));
468 }
469 
470 static int
471 match_ip_addresses(char *reverse_ip, char *intf_ip)
472 {
473         int ip1[4], ip2[4];
474 
475         sscanf(reverse_ip, "%d.%d.%d.%d", &ip1[3], &ip1[2], &ip1[1], &ip1[0]);
476         sscanf(intf_ip, "%d.%d.%d.%d", &ip2[0], &ip2[1], &ip2[2], &ip2[3]);
477 
478         int i;
479         for (i = 0; i < 4; i++) {
480                 if (ip1[i] != ip2[i])
481                         return 0;
482         }
483         return 1;
484 }
485 
486 static void
487 dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip)
488 {
489         struct ifaddrs *ifap, *ifa;
490         struct sockaddr_in6 *sa6;
491 
492         char intf_ip[INET6_ADDRSTRLEN] = "";
493         uint8_t buffer[256];
494         int len;
495 
496         getifaddrs(&ifap);
497         dns_packet_init();
498         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
499                 if (strcmp(ifa->ifa_name, iface->name))
500                         continue;
501                 if (ifa->ifa_addr->sa_family == AF_INET6) {
502                         sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
503                         if (inet_ntop(AF_INET6, &sa6->sin6_addr, intf_ip, INET6_ADDRSTRLEN) == NULL)
504                                 continue;
505 
506                         if (match_ipv6_addresses(reverse_ip, &sa6->sin6_addr)) {
507                                 len = dn_comp(mdns_hostname_local, buffer, sizeof(buffer), NULL, NULL);
508 
509                                 if (len < 1)
510                                         continue;
511 
512                                 dns_packet_answer(name, TYPE_PTR, buffer, len, ttl);
513                         }
514                 }
515         }
516         dns_packet_send(iface, to, 0, 0);
517 
518         freeifaddrs(ifap);
519 }
520 
521 static void
522 dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip)
523 {
524         struct ifaddrs *ifap, *ifa;
525         struct sockaddr_in *sa;
526 
527         char intf_ip[INET_ADDRSTRLEN] = "";
528         uint8_t buffer[256];
529         int len;
530 
531         getifaddrs(&ifap);
532         dns_packet_init();
533         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
534                 if (strcmp(ifa->ifa_name, iface->name))
535                         continue;
536                 if (ifa->ifa_addr->sa_family == AF_INET) {
537                         sa = (struct sockaddr_in *) ifa->ifa_addr;
538                         if (inet_ntop(AF_INET, &sa->sin_addr, intf_ip, INET_ADDRSTRLEN) == NULL)
539                                 continue;
540 
541                         if (match_ip_addresses(reverse_ip, intf_ip)) {
542                                 len = dn_comp(mdns_hostname_local, buffer, sizeof(buffer), NULL, NULL);
543 
544                                 if (len < 1)
545                                         continue;
546 
547                                 dns_packet_answer(name, TYPE_PTR, buffer, len, ttl);
548                         }
549                 }
550         }
551         dns_packet_send(iface, to, 0, 0);
552 
553         freeifaddrs(ifap);
554 }
555 
556 static bool
557 is_reverse_dns_query(const char *name, const char *suffix)
558 {
559         if (!name || !suffix)
560                 return false;
561 
562         size_t name_len = strlen(name);
563         size_t suffix_len = strlen(suffix);
564 
565         if (suffix_len > name_len)
566                 return false;
567 
568         if (strncmp(name + (name_len - suffix_len), suffix, suffix_len) == 0)
569                 return true;
570 
571         return false;
572 }
573 
574 static void
575 parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q)
576 {
577         int is_unicast = (q->class & CLASS_UNICAST) != 0;
578         struct sockaddr *to = NULL;
579         struct hostname *h;
580         char *host, *host6;
581 
582         /* TODO: Multicast if more than one quarter of TTL has passed */
583         if (is_unicast) {
584                 to = from;
585                 if (interface_multicast(iface))
586                         iface = interface_get(iface->name, iface->type | SOCKTYPE_BIT_UNICAST);
587         }
588 
589         DBG(1, "Q -> %s %s\n", dns_type_string(q->type), name);
590 
591         switch (q->type) {
592         case TYPE_ANY:
593                 if (!strcasecmp(name, mdns_hostname_local)) {
594                         dns_reply_a(iface, to, announce_ttl, NULL);
595                         dns_reply_a_additional(iface, to, announce_ttl);
596                         service_reply(iface, to, NULL, NULL, announce_ttl, is_unicast);
597                 }
598                 break;
599 
600         case TYPE_PTR:
601                 if (is_reverse_dns_query(name, ".in-addr.arpa")) {
602                         host = strstr(name, ".in-addr.arpa");
603                         char name_buf[256];
604                         strcpy(name_buf, name);
605                         *host = '\0';
606                         dns_reply_reverse_ip4_mapping(iface, to, announce_ttl, name_buf, name);
607                         break;
608                 }
609 
610                 if (is_reverse_dns_query(name, ".ip6.arpa")) {
611                         host6 = strstr(name, ".ip6.arpa");
612                         char name_buf6[256];
613                         strcpy(name_buf6, name);
614                         *host6 = '\0';
615                         dns_reply_reverse_ip6_mapping(iface, to, announce_ttl, name_buf6, name);
616                         break;
617                 }
618 
619                 if (!strcasecmp(name, C_DNS_SD)) {
620                         service_announce_services(iface, to, announce_ttl);
621                 } else {
622                         if (name[0] == '_') {
623                                 service_reply(iface, to, NULL, name, announce_ttl, is_unicast);
624                         } else {
625                                 /* First dot separates instance name from the rest */
626                                 char *dot = strchr(name, '.');
627 
628                                 if (dot) {
629                                         *dot = '\0';
630                                         service_reply(iface, to, name, dot + 1, announce_ttl, is_unicast);
631                                         *dot = '.';
632                                 }
633                         }
634                 }
635                 break;
636 
637         case TYPE_AAAA:
638         case TYPE_A:
639                 host = strcasestr(name, ".local");
640                 if (host)
641                         *host = '\0';
642                 if (!strcasecmp(umdns_host_label, name)) {
643                         dns_reply_a(iface, to, announce_ttl, NULL);
644                 } else {
645                         if (host)
646                                 *host = '.';
647                         vlist_for_each_element(&hostnames, h, node)
648                                 if (!strcasecmp(h->hostname, name))
649                                         dns_reply_a(iface, to, announce_ttl, h->hostname);
650                 }
651                 break;
652         };
653 }
654 
655 void
656 dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port, uint8_t *buffer, int len)
657 {
658         struct dns_header *h;
659         uint8_t *b = buffer;
660         int rlen = len;
661 
662         h = dns_consume_header(&b, &rlen);
663         if (!h) {
664                 fprintf(stderr, "dropping: bad header\n");
665                 return;
666         }
667 
668         if (h->questions && !interface_multicast(iface) && port != MCAST_PORT)
669                 /* silently drop unicast questions that dont originate from port 5353 */
670                 return;
671 
672         while (h->questions-- > 0) {
673                 char *name = dns_consume_name(buffer, len, &b, &rlen);
674                 struct dns_question *q;
675 
676                 if (!name || rlen < 0) {
677                         fprintf(stderr, "dropping: bad name\n");
678                         return;
679                 }
680 
681                 q = dns_consume_question(&b, &rlen);
682                 if (!q) {
683                         fprintf(stderr, "dropping: bad question\n");
684                         return;
685                 }
686 
687                 if (!(h->flags & FLAG_RESPONSE))
688                         parse_question(iface, from, name, q);
689         }
690 
691         if (!(h->flags & FLAG_RESPONSE))
692                 return;
693 
694         while (h->answers-- > 0)
695                 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1))
696                         return;
697 
698         while (h->authority-- > 0)
699                 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1))
700                         return;
701 
702         while (h->additional-- > 0)
703                 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1))
704                         return;
705 
706 }
707 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt