1#include <sys/types.h> 2#include <sys/socket.h> 3#include <netinet/in.h> 4#include <arpa/inet.h> 5#include <unistd.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <assert.h> 9#include <string.h> 10 11#include <avahi-common/domain.h> 12#include <avahi-common/timeval.h> 13#include <avahi-common/malloc.h> 14#include <avahi-common/error.h> 15#include <avahi-common/address.h> 16 17#include "iface.h" 18#include "socket.h" 19#include "log.h" 20#include "addr-util.h" 21#include "domain-util.h" 22#include "rr-util.h" 23#include "hashmap.h" 24 25#include "llmnr-querier.h" 26#include "llmnr-query-sched.h" 27#include "verify.h" 28#include "llmnr-response.h" 29#include "llmnr-lookup.h" 30#include "dns.h" 31 32/* Server methods */ 33static void avahi_llmnr_server_prepare_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) { 34 assert(s); 35 assert(i); 36 assert(e); 37 assert(e->type == AVAHI_ENTRY_LLMNR); 38 39 avahi_record_list_push(s->llmnr.record_list, 40 e->record, 41 e->flags & AVAHI_PUBLISH_UNIQUE, 42 avahi_llmnr_entry_is_verifying(s, e, i), 43 0); 44 assert(!avahi_record_list_is_empty(s->llmnr.record_list)); 45} 46 47static void avahi_llmnr_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, AvahiKey *key) { 48 assert(s); 49 assert(i); 50 assert(key); 51 52 /* ANY queries*/ 53 if (avahi_key_is_pattern(key)) { 54 AvahiEntry *e; 55 56 for (e = s->llmnr.entries; e; e = e->entries_next) 57 if ((!e->dead && avahi_key_pattern_match(key, e->record->key) && 58 (avahi_llmnr_entry_is_verifying(s, e, i) != -1)) ) 59 60 avahi_llmnr_server_prepare_response(s, i, e); 61 62 } else { 63 AvahiEntry *e; 64 65 /* Other queries */ 66 67 for (e = avahi_hashmap_lookup(s->llmnr.entries_by_key, key); e; e = e->by_key_next) { 68 69 if (!e->dead && 70 (avahi_llmnr_entry_is_verifying(s, e, i) != -1) ) 71 avahi_llmnr_server_prepare_response(s, i, e); 72 } 73 } 74 /* Look for CNAME records */ 75 76 if ((key->clazz == AVAHI_DNS_CLASS_IN || key->clazz == AVAHI_DNS_CLASS_ANY) 77 && key->type != AVAHI_DNS_TYPE_CNAME && key->type != AVAHI_DNS_TYPE_ANY) { 78 AvahiKey *cname_key; 79 if (!(cname_key = avahi_key_new(key->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_CNAME))) 80 return; 81 82 avahi_llmnr_server_prepare_matching_responses(s, i, cname_key); 83 avahi_key_unref(cname_key); 84 } 85 86} 87 88static void avahi_s_cleanup_dead_entries(AvahiServer *s) { 89 assert(s); 90 91 /* Cleanup dead groups (AvahiSEntryGroup) */ 92 if (s->llmnr.need_group_cleanup) { 93 AvahiSEntryGroup *g; 94 95 for (g = s->llmnr.groups; g; g = g->groups_next) { 96 assert(g->type == AVAHI_GROUP_LLMNR); 97 98 if (g->dead) 99 avahi_entry_group_free(s, g); 100 } 101 102 s->llmnr.need_group_cleanup = 0; 103 } 104 105 if (s->llmnr.need_entry_cleanup) { 106 AvahiEntry *e; 107 108 for (e = s->llmnr.entries; e; e = e->entries_next) 109 if (e->dead) 110 avahi_entry_free(s, e); 111 112 s->llmnr.need_entry_cleanup = 0; 113 } 114} 115 116static void llmnr_append_aux_callback(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata) { 117 int *unicast_response = userdata; 118 119 assert(s); 120 assert(r); 121 assert(unicast_response); 122 avahi_record_list_push(s->llmnr.record_list, r, flush_cache, *unicast_response, 1); 123} 124 125static void llmnr_append_aux_records_to_list(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, int unicast_response) { 126 assert(s); 127 assert(r); 128 llmnr_server_enumerate_aux_records(s, i, r, llmnr_append_aux_callback, &unicast_response); 129} 130 131static void llmnr_enum_aux_records(AvahiServer *s, AvahiInterface *i, const char *name, uint16_t type, void (*callback)(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata), void* userdata) { 132 assert(s); 133 assert(i); 134 assert(name); 135 assert(callback); 136 137 if (type == AVAHI_DNS_TYPE_ANY) { 138 AvahiEntry *e; 139 for (e = s->llmnr.entries; e; e = e->entries_next) 140 if (!e->dead && (e->type == AVAHI_ENTRY_LLMNR) && (avahi_llmnr_entry_is_verifying(s, e, i) != -1) && 141 (e->record->key->clazz == AVAHI_DNS_CLASS_IN)&& avahi_domain_equal(name, e->record->key->name)) //Edison 142 callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata); 143 } else { 144 AvahiEntry *e; 145 AvahiKey *k; 146 147 if (!(k = avahi_key_new(name, AVAHI_DNS_CLASS_IN, type))) 148 return; /** OOM */ 149 for (e = avahi_hashmap_lookup(s->llmnr.entries_by_key, k); e; e = e->by_key_next) 150 if (!e->dead && e->type == AVAHI_ENTRY_LLMNR && (avahi_llmnr_entry_is_verifying(s, e, i) != -1)) 151 callback(s, e->record, e->flags & AVAHI_PUBLISH_UNIQUE, userdata); 152 153 avahi_key_unref(k); 154 } 155} 156 157void llmnr_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, void (*callback)(AvahiServer *s, AvahiRecord *r, int flush_cache, void* userdata), void* userdata) { 158 assert(s); 159 assert(i); 160 assert(r); 161 assert(callback); 162 /* Call the specified callback far all records referenced by the one specified in *r */ 163 164 if (r->key->clazz == AVAHI_DNS_CLASS_IN) { 165 if (r->key->type == AVAHI_DNS_TYPE_CNAME) 166 llmnr_enum_aux_records(s, i, r->data.cname.name, AVAHI_DNS_TYPE_ANY, callback, userdata); 167 } 168} 169 170static void avahi_llmnr_server_generate_response( 171 AvahiServer *s, 172 AvahiDnsPacket *p, 173 AvahiInterface *i, 174 const AvahiAddress *address, 175 uint16_t port, 176 int empty_response) { 177 178 /* empty_response == 0 */ 179 /* 1. If the query was for A/AAAA or PTR records we must have only single RR. 180 2. If the query was for ANY type we *should* have only single RR. If more than 181 single RR, we send them in different packets as what should be the value of 'c' 182 and 't' bit in case of multiple records in a single packet is not specified in RFC */ 183 184 /* empty_response == 1 */ 185 /* Ignore the RR's in sl->record_list, just send an empty RR */ 186 187 AvahiDnsPacket *reply = NULL; 188 AvahiRecord *r; 189 int c, t, send_packet = 0; 190 191 if (!empty_response) { 192 /* Get a reply packet */ 193 reply = avahi_llmnr_packet_new_reply(p, 512 + AVAHI_DNS_PACKET_EXTRA_SIZE, 1, !c); 194 195 while ((r = avahi_record_list_next(s->llmnr.record_list, &c, &t, NULL))) { 196 197 llmnr_append_aux_records_to_list(s, i, r, t); //Edison 198 199 /* Append Record */ 200 if (!avahi_llmnr_packet_append_record(reply, r, 30)) { 201 202 /*Send this packet*/ 203 if (avahi_dns_packet_get_field(reply, AVAHI_LLMNR_FIELD_ANCOUNT != 0)) { 204 send_packet = 1; 205 /* If we send rest of the records in a new packet that will be discarded 206 So there is no point sending that. We should have set the T bit and wait 207 for the TCP query but we do not support TCP processing yet. Break*/ 208 /* TODO set errno*/ 209 break; 210 } 211 212 } else { 213 send_packet = 1; 214 /* Increment field */ 215 avahi_dns_packet_inc_field(reply, AVAHI_LLMNR_FIELD_ANCOUNT); 216 avahi_record_unref(r); 217 } 218 } 219 220 } else { 221 reply = avahi_llmnr_packet_new_reply(p, 512 + AVAHI_DNS_PACKET_EXTRA_SIZE, 1, !c); 222 send_packet = 1; 223 } 224 225 avahi_record_list_flush(s->llmnr.record_list); 226 227 if (send_packet) { 228 assert(reply); 229 if (!avahi_schedule_llmnr_response_job(i->llmnr.response_scheduler, reply, address, port)) 230 return; 231 } 232 233 return; 234} 235 236static void prepend_response_packet(int c_bit, AvahiLLMNRQuery *lq, AvahiDnsPacket *p) { 237 AvahiRecord *r = NULL; 238 AvahiKey *key; 239 int n_records; 240 241 assert(lq); 242 assert(p); 243 244 /*TODO Duplicate records*/ 245 n_records = avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_ANCOUNT); 246 247 /* Consume Key first */ 248 key = avahi_llmnr_packet_consume_key(p); 249 250 assert(avahi_key_equal(key, lq->key)); 251 252 if (c_bit) { 253 /* Prepend in C cit set list */ 254 for (; n_records ; n_records--) { 255 if (!(r = avahi_llmnr_packet_consume_record(p))) 256 return; 257 258 avahi_record_list_push(lq->c_bit_set, r, 1, 0, 0); 259 } 260 261 } else { 262 /* Prepend in C bit clear list*/ 263 for (; n_records ; n_records--) { 264 265 if (!(r = avahi_llmnr_packet_consume_record(p))) 266 return; 267 268 avahi_record_list_push(lq->c_bit_clear, r, 0, 0, 0); 269 } 270 } 271} 272 273static void prepend_uniqueness_verification_packet(AvahiLLMNRQuery *lq, const AvahiAddress *src_address) { 274 AvahiVerifierData *vdata; 275 276 assert(lq); 277 assert(src_address); 278 279 vdata = (AvahiVerifierData *)(lq->userdata); 280 281 if (vdata->address) 282 { 283 assert((vdata->t_bit)); 284 /* vdata->address is not NULL => we have already filled this field. Since we 285 issue uniqueness verification query only for those entries that are meant to 286 be UNIQUE, this should either be a duplicate response or entry is not UNIQUE. 287 In any case we put AvahiLLMNREntryVerify object state into AVAHI_CONFLICT. */ 288 if (avahi_address_cmp(vdata->address, src_address) == 0) 289 /* Addresses match, means a duplicate packet */ 290 return; 291 else /* Address don't match => AVAHI_CONFLICT */ 292 vdata->ev->state = AVAHI_CONFLICT; 293 294 } else { 295 /* Set 't' bit */ 296 (vdata->t_bit) = 1; 297 vdata->address = src_address; 298 } 299 300 return; 301} 302 303static void handle_conflict_query (AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i) { 304 AvahiKey *key; 305 306 assert(s); 307 assert(p); 308 assert(i); 309 310 if (!(key = avahi_llmnr_packet_consume_key(p))) 311 return; 312 313 if (avahi_key_is_pattern(key)) { 314 AvahiEntry *e; 315 316 for (e = s->llmnr.entries; e; e = e->entries_next) 317 if ((!e->dead && avahi_key_pattern_match(key, e->record->key) && 318 (avahi_llmnr_entry_is_verifying(s, e, i) == 0)) ) 319 /* Reverify query */ 320 avahi_reverify_entry(s, e); 321 322 } else { 323 AvahiEntry *e; 324 /* Other queries */ 325 for (e = avahi_hashmap_lookup(s->llmnr.entries_by_key, key); e; e = e->by_key_next) 326 if (!e->dead && (avahi_llmnr_entry_is_verifying(s, e, i) == 0)) 327 /* Reverify query */ 328 avahi_reverify_entry(s, e); 329 } 330 331 return; 332} 333 334static void handle_response_packet (AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *src_address, uint16_t port) { 335 uint16_t flags; 336 uint32_t id; 337 AvahiLLMNRQuery *lq; 338 339 assert(s); 340 assert(i); 341 assert(p); 342 assert(src_address); 343 assert(port); 344 345 id = (uint32_t) (avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_ID)); 346 flags = avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_FLAGS); 347 348 /* AvahiLLMNRQuery object that issued this query */ 349 if ( !(lq = avahi_hashmap_lookup(s->llmnr.llmnr_lookup_engine->queries_by_id, &id)) || 350 (lq->dead) ) 351 goto finish; 352 353 assert(lq->type != AVAHI_LLMNR_CONFLICT_QUERY); 354 355 /* Check for the 'tc' bit */ 356 if (flags & AVAHI_LLMNR_FLAG_TC) { 357 /*TODO: TCP Query processing .Not yet supported 358 * Not supported by vista machines either. ;)*/ 359 /** send_tcp_query(sl, i, p, src_address); **/ 360 return; 361 } 362 363 switch(lq->type) { 364 365 case AVAHI_LLMNR_SIMPLE_QUERY : 366 /* Check for 't' bit. For simple queries should be clear*/ 367 if ((flags & AVAHI_LLMNR_FLAG_T) == 1) 368 goto finish; 369 else 370 prepend_response_packet(flags & AVAHI_LLMNR_FLAG_C, lq, p); 371 break; 372 373 case AVAHI_LLMNR_UNIQUENESS_VERIFICATION_QUERY : 374 /* If 't' bit is clear, we will prepend in list according to 'c' bit 375 and will check at last whether there is already a conflict about this entry*/ 376 if (!(flags & AVAHI_LLMNR_FLAG_T)) 377 prepend_response_packet(flags & AVAHI_LLMNR_FLAG_C, lq, p); 378 else /* 't' bit is set => we are not concerned with 'c' bit now*/ 379 prepend_uniqueness_verification_packet(lq, src_address); 380 break; 381 382 default : 383 break; 384 } 385 return; 386 387finish: 388 avahi_dns_packet_free(p); 389 return; 390} 391 392static void handle_query_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *src_address, uint16_t port) { 393 AvahiKey *key, *new_key; 394 395 assert(s); 396 assert(i); 397 assert(p); 398 assert(src_address); 399 assert(port); 400 assert(avahi_record_list_is_empty(s->llmnr.record_list)); 401 402 if (!(key = avahi_llmnr_packet_consume_key(p))) 403 return; 404 405 /* Fill sl->record_list with valid RR/'s, if any */ 406 avahi_llmnr_server_prepare_matching_responses(s, i, key); 407 408 if (!avahi_record_list_is_empty(s->llmnr.record_list)) { 409 avahi_llmnr_server_generate_response(s, p, i, src_address, port, 0); 410 avahi_key_unref(key); 411 412 } else if (!(key->type == AVAHI_DNS_TYPE_ANY)) { 413 414 /* We don't have any valid verified record for this key. 415 Now we check for records with 'type = AVAHI_DNS_TYPE_ANY' 416 with same name to see if we are autoritative for that name 417 for another type of query. In that case we send an empty 418 response packet. */ 419 new_key = avahi_key_new(key->name, key->clazz, AVAHI_DNS_TYPE_ANY); 420 avahi_llmnr_server_prepare_matching_responses(s, i, new_key); 421 avahi_key_unref(new_key); 422 423 if (!avahi_record_list_is_empty(s->llmnr.record_list)) 424 /* We do have record for type ANY. Send an empty response */ 425 avahi_llmnr_server_generate_response(s, p, i, src_address, port, 1); 426 } 427 428 return; 429} 430 431static int originates_from_local_iface(AvahiServer *s, AvahiIfIndex iface, const AvahiAddress *a, uint16_t port) { 432 433 assert(s); 434 assert(iface != AVAHI_IF_UNSPEC); 435 assert(a); 436 437 if (port != AVAHI_LLMNR_PORT) 438 return 0; 439 440 return avahi_interface_has_address(s->monitor, iface, a); 441} 442 443 444static int is_llmnr_mcast_address(const AvahiAddress *a) { 445 AvahiAddress b; 446 assert(a); 447 448 avahi_address_parse(a->proto == AVAHI_PROTO_INET ? AVAHI_IPV4_LLMNR_GROUP : AVAHI_IPV6_LLMNR_GROUP, a->proto, &b); 449 450 return avahi_address_cmp(a, &b) == 0; 451} 452 453static void dispatch_packet ( 454 AvahiServer *s, 455 AvahiDnsPacket *p, 456 const AvahiAddress *src_address, 457 uint16_t port, 458 const AvahiAddress *dst_address, 459 AvahiIfIndex iface, 460 int ttl) { 461 462 /* Get Interface here*/ 463 AvahiInterface *i; 464 uint16_t flags; 465 466 assert(s); 467 assert(p); 468 assert(src_address); 469 assert(dst_address); 470 assert(iface > 0); 471 assert(src_address->proto == dst_address->proto); 472 473 474 if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, src_address->proto)) || !i->llmnr.verifying) 475 return; 476 477 /* Discard our own packets */ 478 if (originates_from_local_iface(s, iface, src_address, port)) 479 return; 480 481 if (avahi_llmnr_packet_check_valid(p) < 0) 482 return; 483 484 flags = avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_FLAGS); 485 486 if (!(flags & AVAHI_LLMNR_FLAG_QR)) { 487 488 /* UDP queries should be multicast (Queries can be sent over any port) 489 So we don't check for the port here.*/ 490 if (!(is_llmnr_mcast_address(dst_address))) 491 return; 492 493 /* Make sure 'tc' bit is clear. Ignore 'rcode' and 't' bitsTODO, TC bit set in Vista Packets*/ 494 if ( (flags & AVAHI_LLMNR_FLAG_TC) || 495 (avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_QDCOUNT) != 1 ) || 496 (avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_ANCOUNT) != 0) || 497 (avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_NSCOUNT) != 0) ) 498 return; 499 500 /* Check for the 'c' bit */ 501 if (!(flags & AVAHI_LLMNR_FLAG_C)) 502 /* Simple_LLMNR_Query packet*/ 503 handle_query_packet(s, p, i, src_address, port); 504 505 /* Received a conflict query. We don't respond to this query. 506 Rather start uniquness verification process.*/ 507 else 508 handle_conflict_query(s, p, i); 509 510 } else /* Response packet */ { 511 512 /* Response must be unicast and must be sent through standard 513 LLMNR port*/ 514 if ((is_llmnr_mcast_address(dst_address)) && 515 (port != AVAHI_LLMNR_PORT)) 516 return; 517 518 /* RCODE must be clear for LLMNR unicast UDP responses */ 519 if ((flags & AVAHI_LLMNR_FLAG_RCODE)) 520 return; 521 522 /* sl->server->config.check_response_ttl, same goes for LLMNR*/ 523 if (ttl != 255 && s->config.check_response_ttl) { 524 avahi_log_warn("Received response with invalid TTL %u on interface '%s.%i'.", ttl, i->hardware->name, i->protocol); 525 return; 526 } 527 528 if (avahi_dns_packet_get_field(p, AVAHI_LLMNR_FIELD_QDCOUNT) != 1) 529 return; 530 531 handle_response_packet(s, p, i, src_address, port); 532 } 533 534 return; 535} 536 537 538static void llmnr_socket_event(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata) { 539 AvahiServer *s = userdata; 540 AvahiAddress dest, src; 541 AvahiDnsPacket *p = NULL; 542 /* Pass the Interface Index from this function */ 543 AvahiIfIndex iface; 544 545 uint16_t port; 546 uint8_t ttl; 547 548 assert(w); 549 assert(fd >= 0); 550 assert(event & AVAHI_WATCH_IN); 551 552 if (fd == s->llmnr.fd_ipv4) { 553 dest.proto = src.proto = AVAHI_PROTO_INET; 554 p = avahi_recv_dns_packet_ipv4(s->llmnr.fd_ipv4, &src.data.ipv4, &port, &dest.data.ipv4, &iface, &ttl); 555 556 } else { 557 assert(fd == s->llmnr.fd_ipv6) ; 558 dest.proto = src.proto = AVAHI_PROTO_INET6 ; 559 p = avahi_recv_dns_packet_ipv6(s->llmnr.fd_ipv6, &src.data.ipv6, &port, &dest.data.ipv6, &iface, &ttl); 560 } 561 562 if (p) { 563 /* Find Interface Index if iface == AVAHI_IF_UNSPEC presently with the help of dest address */ 564 if (iface == AVAHI_IF_UNSPEC) 565 iface = avahi_find_interface_for_address(s->monitor, &dest); 566 567 /* we should have some specific value in iface otherwise we can't dispatch the packet */ 568 if (iface != AVAHI_IF_UNSPEC) 569 dispatch_packet(s, p, &src, port, &dest, iface, ttl); 570 else 571 avahi_log_error("Invalid address"); 572 573 avahi_dns_packet_free(p); 574 575 /* TODO clean-up */ 576 avahi_s_cleanup_dead_entries(s); 577 } 578} 579 580int setup_llmnr_sockets(AvahiServer *s) { 581 assert(s); 582 583 s->llmnr.fd_ipv4 = s->config.use_ipv4 ? avahi_open_socket_ipv4(s->config.disallow_other_stacks, AVAHI_LLMNR) : -1; 584 s->llmnr.fd_ipv6 = s->config.use_ipv6 ? avahi_open_socket_ipv6(s->config.disallow_other_stacks, AVAHI_LLMNR) : -1; 585 586 if (s->llmnr.fd_ipv6 < 0 && s->llmnr.fd_ipv4 < 0) 587 return AVAHI_ERR_NO_NETWORK; 588 589 if (s->llmnr.fd_ipv4 < 0 && s->config.use_ipv4) 590 avahi_log_notice("Failed to create IPv4 LLMNR socket, proceeding in IPv6 only mode"); 591 else if (s->llmnr.fd_ipv6 < 0 && s->config.use_ipv6) 592 avahi_log_notice("Failed to create IPv6 LLMNR socket, proceeding in IPv4 only mode"); 593 594 s->llmnr.watch_ipv4 = s->llmnr.watch_ipv6 = NULL; 595 596 if (s->llmnr.fd_ipv4 >= 0) 597 s->llmnr.watch_ipv4 = s->poll_api->watch_new(s->poll_api, s->llmnr.fd_ipv4, AVAHI_WATCH_IN, llmnr_socket_event, s); 598 if (s->llmnr.fd_ipv6 >= 0) 599 s->llmnr.watch_ipv6 = s->poll_api->watch_new(s->poll_api, s->llmnr.fd_ipv6, AVAHI_WATCH_IN, llmnr_socket_event, s); 600 601 return 0; 602} 603 604