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) 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, mdns_hostname_local); 208 209 freeifaddrs(ifap); 210 } 211 212 static int 213 scan_name(const uint8_t *buffer, int len) 214 { 215 int offset = 0; 216 217 while (len && (*buffer != '\0')) { 218 int l = *buffer; 219 220 if (IS_COMPRESSED(l)) 221 return offset + 2; 222 223 if (l + 1 > len) return -1; 224 len -= l + 1; 225 offset += l + 1; 226 buffer += l + 1; 227 } 228 229 if (!len || !offset || (*buffer != '\0')) 230 return -1; 231 232 return offset + 1; 233 } 234 235 static struct dns_header* 236 dns_consume_header(uint8_t **data, int *len) 237 { 238 struct dns_header *h = (struct dns_header *) *data; 239 240 if (*len < sizeof(struct dns_header)) 241 return NULL; 242 243 h->id = be16_to_cpu(h->id); 244 h->flags = be16_to_cpu(h->flags); 245 h->questions = be16_to_cpu(h->questions); 246 h->answers = be16_to_cpu(h->answers); 247 h->authority = be16_to_cpu(h->authority); 248 h->additional = be16_to_cpu(h->additional); 249 250 *len -= sizeof(struct dns_header); 251 *data += sizeof(struct dns_header); 252 253 return h; 254 } 255 256 static struct dns_question* 257 dns_consume_question(uint8_t **data, int *len) 258 { 259 struct dns_question *q = (struct dns_question *) *data; 260 261 if (*len < sizeof(struct dns_question)) 262 return NULL; 263 264 q->type = be16_to_cpu(q->type); 265 q->class = be16_to_cpu(q->class); 266 267 *len -= sizeof(struct dns_question); 268 *data += sizeof(struct dns_question); 269 270 return q; 271 } 272 273 static struct dns_answer* 274 dns_consume_answer(uint8_t **data, int *len) 275 { 276 struct dns_answer *a = (struct dns_answer *) *data; 277 278 if (*len < sizeof(struct dns_answer)) 279 return NULL; 280 281 a->type = be16_to_cpu(a->type); 282 a->class = be16_to_cpu(a->class); 283 a->ttl = be32_to_cpu(a->ttl); 284 a->rdlength = be16_to_cpu(a->rdlength); 285 286 *len -= sizeof(struct dns_answer); 287 *data += sizeof(struct dns_answer); 288 289 return a; 290 } 291 292 static char * 293 dns_consume_name(const uint8_t *base, int blen, uint8_t **data, int *len) 294 { 295 int nlen = scan_name(*data, *len); 296 297 if (nlen < 1) 298 return NULL; 299 300 if (dn_expand(base, base + blen, *data, name_buffer, MAX_NAME_LEN) < 0) { 301 perror("dns_consume_name/dn_expand"); 302 return NULL; 303 } 304 305 *len -= nlen; 306 *data += nlen; 307 308 return name_buffer; 309 } 310 311 static int parse_answer(struct interface *iface, struct sockaddr *from, 312 uint8_t *buffer, int len, uint8_t **b, int *rlen, 313 int cache) 314 { 315 char *name = dns_consume_name(buffer, len, b, rlen); 316 struct dns_answer *a; 317 uint8_t *rdata; 318 319 if (!name || *rlen < 0) { 320 fprintf(stderr, "dropping: bad question\n"); 321 return -1; 322 } 323 324 a = dns_consume_answer(b, rlen); 325 if (!a) { 326 fprintf(stderr, "dropping: bad question\n"); 327 return -1; 328 } 329 330 if ((a->class & ~CLASS_FLUSH) != CLASS_IN) 331 return -1; 332 333 rdata = *b; 334 if (a->rdlength > *rlen) { 335 fprintf(stderr, "dropping: bad question\n"); 336 return -1; 337 } 338 339 *rlen -= a->rdlength; 340 *b += a->rdlength; 341 342 if (cache) 343 cache_answer(iface, from, buffer, len, name, a, rdata, a->class & CLASS_FLUSH); 344 345 return 0; 346 } 347 348 static void 349 parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q) 350 { 351 struct sockaddr *to = NULL; 352 char *host; 353 354 /* TODO: Multicast if more than one quarter of TTL has passed */ 355 if (q->class & CLASS_UNICAST) { 356 to = from; 357 if (iface->multicast) 358 iface = iface->peer; 359 } 360 361 DBG(1, "Q -> %s %s\n", dns_type_string(q->type), name); 362 363 switch (q->type) { 364 case TYPE_ANY: 365 if (!strcmp(name, mdns_hostname_local)) { 366 dns_reply_a(iface, to, announce_ttl); 367 service_reply(iface, to, NULL, NULL, announce_ttl); 368 } 369 break; 370 371 case TYPE_PTR: 372 if (!strcmp(name, C_DNS_SD)) { 373 dns_reply_a(iface, to, announce_ttl); 374 service_announce_services(iface, to, announce_ttl); 375 } else { 376 if (name[0] == '_') { 377 service_reply(iface, to, NULL, name, announce_ttl); 378 } else { 379 /* First dot separates instance name from the rest */ 380 char *dot = strchr(name, '.'); 381 382 if (dot) { 383 *dot = '\0'; 384 service_reply(iface, to, name, dot + 1, announce_ttl); 385 *dot = '.'; 386 } 387 } 388 } 389 break; 390 391 case TYPE_AAAA: 392 case TYPE_A: 393 host = strstr(name, ".local"); 394 if (host) 395 *host = '\0'; 396 if (!strcmp(umdns_host_label, name)) 397 dns_reply_a(iface, to, announce_ttl); 398 break; 399 }; 400 } 401 402 void 403 dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port, uint8_t *buffer, int len) 404 { 405 struct dns_header *h; 406 uint8_t *b = buffer; 407 int rlen = len; 408 409 h = dns_consume_header(&b, &rlen); 410 if (!h) { 411 fprintf(stderr, "dropping: bad header\n"); 412 return; 413 } 414 415 if (h->questions && !iface->multicast && port != MCAST_PORT) 416 /* silently drop unicast questions that dont originate from port 5353 */ 417 return; 418 419 while (h->questions-- > 0) { 420 char *name = dns_consume_name(buffer, len, &b, &rlen); 421 struct dns_question *q; 422 423 if (!name || rlen < 0) { 424 fprintf(stderr, "dropping: bad name\n"); 425 return; 426 } 427 428 q = dns_consume_question(&b, &rlen); 429 if (!q) { 430 fprintf(stderr, "dropping: bad question\n"); 431 return; 432 } 433 434 if (!(h->flags & FLAG_RESPONSE)) 435 parse_question(iface, from, name, q); 436 } 437 438 if (!(h->flags & FLAG_RESPONSE)) 439 return; 440 441 while (h->answers-- > 0) 442 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1)) 443 return; 444 445 while (h->authority-- > 0) 446 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1)) 447 return; 448 449 while (h->additional-- > 0) 450 if (parse_answer(iface, from, buffer, len, &b, &rlen, 1)) 451 return; 452 453 } 454
This page was automatically generated by LXR 0.3.1. • OpenWrt