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 #include <sys/types.h> 15 #include <sys/stat.h> 16 17 #include <fcntl.h> 18 #include <ifaddrs.h> 19 #include <time.h> 20 #include <stdio.h> 21 #include <unistd.h> 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <arpa/nameser.h> 27 #include <resolv.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include <libubox/uloop.h> 32 #include <libubox/usock.h> 33 #include <libubox/utils.h> 34 35 #include "announce.h" 36 #include "util.h" 37 #include "dns.h" 38 #include "cache.h" 39 #include "service.h" 40 #include "interface.h" 41 42 static char name_buffer[MAX_NAME_LEN + 1]; 43 static char dns_buffer[MAX_NAME_LEN]; 44 static struct blob_buf ans_buf; 45 46 const char* 47 dns_type_string(uint16_t type) 48 { 49 static const struct { 50 uint16_t type; 51 char str[5]; 52 } type_str[] = { 53 { TYPE_A, "A" }, 54 { TYPE_AAAA, "AAAA" }, 55 { TYPE_PTR, "PTR" }, 56 { TYPE_TXT, "TXT" }, 57 { TYPE_SRV, "SRV" }, 58 { TYPE_ANY, "ANY" }, 59 }; 60 int i; 61 62 for (i = 0; i < ARRAY_SIZE(type_str); i++) { 63 if (type == type_str[i].type) 64 return type_str[i].str; 65 } 66 67 return "N/A"; 68 } 69 70 void 71 dns_send_question(struct interface *iface, struct sockaddr *to, 72 const char *question, int type, int multicast) 73 { 74 static struct dns_header h; 75 static struct dns_question q; 76 static struct iovec iov[] = { 77 { 78 .iov_base = &h, 79 .iov_len = sizeof(h), 80 }, 81 { 82 .iov_base = dns_buffer, 83 }, 84 { 85 .iov_base = &q, 86 .iov_len = sizeof(q), 87 } 88 }; 89 int len; 90 91 h.questions = cpu_to_be16(1); 92 q.class = cpu_to_be16((multicast ? 0 : CLASS_UNICAST) | 1); 93 q.type = cpu_to_be16(type); 94 95 len = dn_comp(question, (void *) dns_buffer, sizeof(dns_buffer), NULL, NULL); 96 if (len < 1) 97 return; 98 99 iov[1].iov_len = len; 100 101 DBG(1, "Q <- %s %s\n", dns_type_string(type), question); 102 if (interface_send_packet(iface, to, iov, ARRAY_SIZE(iov)) < 0) 103 perror("failed to send question"); 104 } 105 106 107 struct dns_reply { 108 int type; 109 struct dns_answer a; 110 uint16_t rdlength; 111 uint8_t *rdata; 112 char *buffer; 113 }; 114 115 static int dns_answer_cnt; 116 117 void 118 dns_init_answer(void) 119 { 120 dns_answer_cnt = 0; 121 blob_buf_init(&ans_buf, 0); 122 } 123 124 void 125 dns_add_answer(int type, const uint8_t *rdata, uint16_t rdlength, int ttl) 126 { 127 struct blob_attr *attr; 128 struct dns_answer *a; 129 130 attr = blob_new(&ans_buf, 0, sizeof(*a) + rdlength); 131 a = blob_data(attr); 132 a->type = cpu_to_be16(type); 133 a->class = cpu_to_be16(1); 134 a->ttl = cpu_to_be32(ttl); 135 a->rdlength = cpu_to_be16(rdlength); 136 memcpy(a + 1, rdata, rdlength); 137 138 dns_answer_cnt++; 139 } 140 141 void 142 dns_send_answer(struct interface *iface, struct sockaddr *to, const char *answer) 143 { 144 uint8_t buffer[256]; 145 struct blob_attr *attr; 146 struct dns_header h = { 0 }; 147 struct iovec *iov; 148 int answer_len, rem; 149 int n_iov = 0; 150 151 if (!dns_answer_cnt) 152 return; 153 154 h.answers = cpu_to_be16(dns_answer_cnt); 155 h.flags = cpu_to_be16(0x8400); 156 157 iov = alloca(sizeof(struct iovec) * ((dns_answer_cnt * 2) + 1)); 158 159 iov[n_iov].iov_base = &h; 160 iov[n_iov].iov_len = sizeof(struct dns_header); 161 n_iov++; 162 163 answer_len = dn_comp(answer, buffer, sizeof(buffer), NULL, NULL); 164 if (answer_len < 1) 165 return; 166 167 blob_for_each_attr(attr, ans_buf.head, rem) { 168 struct dns_answer *a = blob_data(attr); 169 170 iov[n_iov].iov_base = buffer; 171 iov[n_iov].iov_len = answer_len; 172 n_iov++; 173 174 iov[n_iov].iov_base = blob_data(attr); 175 iov[n_iov].iov_len = blob_len(attr); 176 n_iov++; 177 178 DBG(1, "A <- %s %s\n", dns_type_string(be16_to_cpu(a->type)), answer); 179 } 180 181 if (interface_send_packet(iface, to, iov, n_iov) < 0) 182 perror("failed to send answer"); 183 } 184 185 void 186 dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname) 187 { 188 struct ifaddrs *ifap, *ifa; 189 struct sockaddr_in *sa; 190 struct sockaddr_in6 *sa6; 191 192 getifaddrs(&ifap); 193 194 dns_init_answer(); 195 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 196 if (strcmp(ifa->ifa_name, iface->name)) 197 continue; 198 if (ifa->ifa_addr->sa_family == AF_INET) { 199 sa = (struct sockaddr_in *) ifa->ifa_addr; 200 dns_add_answer(TYPE_A, (uint8_t *) &sa->sin_addr, 4, ttl); 201 } 202 if (ifa->ifa_addr->sa_family == AF_INET6) { 203 sa6 = (struct sockaddr_in6 *) ifa->ifa_addr; 204 dns_add_answer(TYPE_AAAA, (uint8_t *) &sa6->sin6_addr, 16, ttl); 205 } 206 } 207 dns_send_answer(iface, to, hostname ? hostname : mdns_hostname_local); 208 209 freeifaddrs(ifap); 210 } 211 212 void 213 dns_reply_a_additional(struct interface *iface, struct sockaddr *to, int ttl) 214 { 215 struct hostname *h; 216 217 vlist_for_each_element(&hostnames, h, node) 218 dns_reply_a(iface, to, ttl, h->hostname); 219 } 220 221 static int 222 scan_name(const uint8_t *buffer, int len) 223 { 224 int offset = 0; 225 226 while (len && (*buffer != '\0')) { 227 int l = *buffer; 228 229 if (IS_COMPRESSED(l)) 230 return offset + 2; 231 232 if (l + 1 > len) return -1; 233 len -= l + 1; 234 offset += l + 1; 235 buffer += l + 1; 236 } 237 238 if (!len || !offset || (*buffer != '\0')) 239 return -1; 240 241 return offset + 1; 242 } 243 244 static struct dns_header* 245 dns_consume_header(uint8_t **data, int *len) 246 { 247 struct dns_header *h = (struct dns_header *) *data; 248 249 if (*len < sizeof(struct dns_header)) 250 return NULL; 251 252 h->id = be16_to_cpu(h->id); 253 h->flags = be16_to_cpu(h->flags); 254 h->questions = be16_to_cpu(h->questions); 255 h->answers = be16_to_cpu(h->answers); 256 h->authority = be16_to_cpu(h->authority); 257 h->additional = be16_to_cpu(h->additional); 258 259 *len -= sizeof(struct dns_header); 260 *data += sizeof(struct dns_header); 261 262 return h; 263 } 264 265 static struct dns_question* 266 dns_consume_question(uint8_t **data, int *len) 267 { 268 struct dns_question *q = (struct dns_question *) *data; 269 270 if (*len < sizeof(struct dns_question)) 271 return NULL; 272 273 q->type = be16_to_cpu(q->type); 274 q->class = be16_to_cpu(q->class); 275 276 *len -= sizeof(struct dns_question); 277 *data += sizeof(struct dns_question); 278 279 return q; 280 } 281 282 static struct dns_answer* 283 dns_consume_answer(uint8_t **data, int *len) 284 { 285 struct dns_answer *a = (struct dns_answer *) *data; 286 287 if (*len < sizeof(struct dns_answer)) 288 return NULL; 289 290 a->type = be16_to_cpu(a->type); 291 a->class = be16_to_cpu(a->class); 292 a->ttl = be32_to_cpu(a->ttl); 293 a->rdlength = be16_to_cpu(a->rdlength); 294 295 *len -= sizeof(struct dns_answer); 296 *data += sizeof(struct dns_answer); 297 298 return a; 299 } 300 301 static char * 302 dns_consume_name(const uint8_t *base, int blen, uint8_t **data, int *len) 303 { 304 int nlen = scan_name(*data, *len); 305 306 if (nlen < 1) 307 return NULL; 308 309 if (dn_expand(base, base + blen, *data, name_buffer, MAX_NAME_LEN) < 0) { 310 perror("dns_consume_name/dn_expand"); 311 return NULL; 312 } 313 314 *len -= nlen; 315 *data += nlen; 316 317 return name_buffer; 318 } 319 320 static int parse_answer(struct interface *iface, struct sockaddr *from, 321 uint8_t *buffer, int len, uint8_t **b, int *rlen, 322 int cache) 323 { 324 char *name = dns_consume_name(buffer, len, b, rlen); 325 struct dns_answer *a; 326 uint8_t *rdata; 327 328 if (!name || *rlen < 0) { 329 fprintf(stderr, "dropping: bad question\n"); 330 return -1; 331 } 332 333 a = dns_consume_answer(b, rlen); 334 if (!a) { 335 fprintf(stderr, "dropping: bad question\n"); 336 return -1; 337 } 338 339 if ((a->class & ~CLASS_FLUSH) != CLASS_IN) 340 return -1; 341 342 rdata = *b; 343 if (a->rdlength > *rlen) { 344 fprintf(stderr, "dropping: bad question\n"); 345 return -1; 346 } 347 348 *rlen -= a->rdlength; 349 *b += a->rdlength; 350 351 if (cache) 352 cache_answer(iface, from, buffer, len, name, a, rdata, a->class & CLASS_FLUSH); 353 354 return 0; 355 } 356 357 static void 358 parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q) 359 { 360 struct sockaddr *to = NULL; 361 struct hostname *h; 362 char *host; 363 364 /* TODO: Multicast if more than one quarter of TTL has passed */ 365 if (q->class & CLASS_UNICAST) { 366 to = from; 367 if (interface_multicast(iface)) 368 iface = interface_get(iface->name, iface->type | SOCKTYPE_BIT_UNICAST); 369 } 370 371 DBG(1, "Q -> %s %s\n", dns_type_string(q->type), name); 372 373 switch (q->type) { 374 case TYPE_ANY: 375 if (!strcmp(name, mdns_hostname_local)) { 376 dns_reply_a(iface, to, announce_ttl, NULL); 377 dns_reply_a_additional(iface, to, announce_ttl); 378 service_reply(iface, to, NULL, NULL, announce_ttl); 379 } 380 break; 381 382 case TYPE_PTR: 383 if (!strcmp(name, C_DNS_SD)) { 384 dns_reply_a(iface, to, announce_ttl, NULL); 385 dns_reply_a_additional(iface, to, announce_ttl); 386 service_announce_services(iface, to, announce_ttl); 387 } else { 388 if (name[0] == '_') { 389 service_reply(iface, to, NULL, name, announce_ttl); 390 } else { 391 /* First dot separates instance name from the rest */ 392 char *dot = strchr(name, '.'); 393 394 if (dot) { 395 *dot = '\0'; 396 service_reply(iface, to, name, dot + 1, announce_ttl); 397 *dot = '.'; 398 } 399 } 400 } 401 break; 402 403 case TYPE_AAAA: 404 case TYPE_A: 405 host = strstr(name, ".local"); 406 if (host) 407 *host = '\0'; 408 if (!strcmp(umdns_host_label, name)) { 409 dns_reply_a(iface, to, announce_ttl, NULL); 410 } else { 411 if (host) 412 *host = '.'; 413 vlist_for_each_element(&hostnames, h, node) 414 if (!strcmp(h->hostname, name)) 415 dns_reply_a(iface, to, announce_ttl, h->hostname); 416 } 417 break; 418 }; 419 } 420 421 void 422 dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port, uint8_t *buffer, int len) 423 { 424 struct dns_header *h; 425 uint8_t *b = buffer; 426 int rlen = len; 427 428 h = dns_consume_header(&b, &rlen); 429 if (!h) { 430 fprintf(stderr, "dropping: bad header\n"); 431 return; 432 } 433 434 if (h->questions && !interface_multicast(iface) && port != MCAST_PORT) 435 /* silently drop unicast questions that dont originate from port 5353 */ 436 return; 437 438 while (h->questions-- > 0) { 439 char *name = dns_consume_name(buffer, len, &b, &rlen); 440 struct dns_question *q; 441 442 if (!name || rlen < 0) { 443 fprintf(stderr, "dropping: bad name\n"); 444 return; 445 } 446 447 q = dns_consume_question(&b, &rlen); 448 if (!q) { 449 fprintf(stderr, "dropping: bad question\n"); 450 return; 451 } 452 453 if (!(h->flags & FLAG_RESPONSE)) 454 parse_question(iface, from, name, q); 455 } 456 457 if (!(h->flags & FLAG_RESPONSE)) 458 return; 459 460 while (h->answers-- > 0) 461 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1)) 462 return; 463 464 while (h->authority-- > 0) 465 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1)) 466 return; 467 468 while (h->additional-- > 0) 469 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1)) 470 return; 471 472 } 473
This page was automatically generated by LXR 0.3.1. • OpenWrt