1#include <string.h> 2#include <stdio.h> 3 4#include <avahi-common/timeval.h> 5#include <avahi-common/malloc.h> 6 7#include "log.h" 8#include "rr-util.h" 9 10#include "verify.h" 11 12static void check_established (AvahiSEntryGroup *group) { 13 assert(group); 14 assert(group->type == AVAHI_GROUP_LLMNR); 15 16 /* Check for the state */ 17 if (group->proto.llmnr.n_verifying == 0) 18 avahi_s_entry_group_change_state(group, AVAHI_ENTRY_GROUP_LLMNR_ESTABLISHED); 19} 20 21/* Decrease the n_verifying counter and free the 'lq' object */ 22static void decrease_n_verify(AvahiLLMNREntryVerify *ev) { 23 assert(ev); 24 assert(ev->e->group->type == AVAHI_GROUP_LLMNR); 25 26 /* 27 * 1. Group is new and presently the state is verifying and decreasing the counter 28 * may enter the group in established state. 29 * 2. Group is already established and we are registering a new entry, we should have 30 * n_verifying greater than zero 31 */ 32 assert((ev->e->group->state == AVAHI_ENTRY_GROUP_LLMNR_VERIFYING) || 33 (ev->e->group->proto.llmnr.n_verifying > 0)); 34 35 --ev->e->group->proto.llmnr.n_verifying; 36 check_established(ev->e->group); 37} 38 39static void withdraw_llmnr_entry(AvahiServer *s, AvahiEntry *e) { 40 assert(s); 41 assert(e); 42 assert(e->type == AVAHI_ENTRY_LLMNR); 43 44 /* Withdraw the specified entry, and if is part of an entry group, 45 * put that into LLMNR_COLLISION state */ 46 if (e->dead) 47 return; 48 49 if (e->group) { 50 AvahiEntry *k; 51 assert(e->group->type == AVAHI_GROUP_LLMNR); 52 53 /* Withdraw all entries of that group */ 54 for (k = e->group->entries; k; k = k->by_group_next) { 55 assert(k->type == AVAHI_ENTRY_LLMNR); 56 if (!k->dead) 57 k->dead = 1; 58 } 59 60 e->group->proto.llmnr.n_verifying = 0; 61 avahi_s_entry_group_change_state(e->group, AVAHI_ENTRY_GROUP_LLMNR_COLLISION); 62 } else 63 e->dead = 1; 64 65 s->llmnr.need_entry_cleanup = 1; 66 return; 67} 68 69/* This function is called when 'AvahiLLMNRQuery' has been processed completely. 70Based on the data we get in 'userdata', state of the 'AvahiLLMNREntryVerifier' is decided*/ 71static void query_callback( 72 AvahiIfIndex idx, 73 AvahiProtocol protocol, 74 AvahiRecord *r, 75 void *userdata) { 76 /* Get AvahiLLMNREntryVerify object, responder address and 'T' bit info, if any*/ 77 78 AvahiVerifierData *vdata = userdata; 79 int win, t_bit ; 80 81 AvahiLLMNREntryVerify *ev; 82 const AvahiAddress *address; 83 84 win = 0; 85 ev = (vdata->ev); 86 address = (vdata->address); 87 t_bit = (vdata->t_bit); 88 89 /* May be by the time we come back in this function due to conflict in some other entry 90 of the group this entry belongs to, this entry has already been put up in the dead state.*/ 91 if (ev->e->dead) 92 return; 93 94 assert(AVAHI_IF_VALID(idx)); 95 assert(AVAHI_PROTO_VALID(protocol)); 96 assert(userdata); 97 assert(ev->e->type == AVAHI_ENTRY_LLMNR); 98 assert(!ev->e->dead); 99 100 /* Start comparing values.*/ 101 if (ev->state == AVAHI_CONFLICT) { 102 /* Set by handle_response function*/ 103 /* There is already a conflict about this key or name is not UNIQUE */ 104 /* Withdraw this Entry*/ 105 withdraw_llmnr_entry(ev->s, ev->e); 106 } else { 107 if (!r && !address) { 108 /* No record found for this key. Our name is unique. */ 109 /*char *t; 110 t = avahi_record_to_string(ev->e->record); 111 avahi_log_info("LLMNR Entry Verified\n %s on interface index (%d) and protocol : %s", 112 t, 113 ev->interface->hardware->index, 114 avahi_proto_to_string(ev->interface->protocol));*/ 115 116 ev->state = AVAHI_VERIFIED; 117 118 if (ev->e->group) 119 decrease_n_verify(ev); 120 } else { 121 /* We may have two cases now !r && address || r && !address 122 r && !address when T bit is clear 123 !r && address when T bit is set */ 124 125 /* So check 'T' bit first*/ 126 if (!(t_bit)) { 127 /* Assert that we had a response for this key */ 128 assert(r); 129 130 /*Another host has already claimed for this name and is using it.*/ 131 ev->state = AVAHI_CONFLICT; 132 133 /* withdraw this entry */ 134 withdraw_llmnr_entry(ev->s, ev->e); 135 136 } else { 137 /* 'T' bit is set. Now we compare two IP addresses lexicographically*/ 138 assert(protocol == address->proto); 139 140 /* Source IP address = which is being used by interface to join LLMNR group 141 We compare that address and responder address */ 142 assert(ev->interface->llmnr.llmnr_joined); 143 144 if ( (protocol == AVAHI_PROTO_INET) && 145 (memcmp(&(ev->interface->llmnr.local_llmnr_address.data.ipv4.address), &(address->data.ipv4.address), sizeof(AvahiIPv4Address))) ) 146 win = 1; 147 else /*( protocol == AVAHI_PROTO_INET6) */ 148 if (memcmp(&(ev->interface->llmnr.local_llmnr_address.data.ipv6.address), &(address->data.ipv6.address), sizeof(AvahiIPv6Address))) 149 win = 1; 150 151 if (win) { 152 /* We can claim this name */ 153 ev->state = AVAHI_ESTABLISHED; 154 decrease_n_verify(ev); 155 } else { 156 ev->state = AVAHI_CONFLICT; 157 withdraw_llmnr_entry(ev->s, ev->e); 158 } 159 } 160 } 161 } 162 163 ev->lq = NULL; 164 return; 165} 166 167static void remove_verifier(AvahiServer *s, AvahiLLMNREntryVerify *ev) { 168 assert(s); 169 assert(ev); 170 assert(ev->e->type == AVAHI_ENTRY_LLMNR); 171 172 if (ev->lq) 173 avahi_llmnr_query_scheduler_withdraw_by_id(ev->interface->llmnr.query_scheduler, ev->lq->post_id); 174 175 AVAHI_LLIST_REMOVE(AvahiLLMNREntryVerify, by_interface, ev->interface->llmnr.verifiers, ev); 176 AVAHI_LLIST_REMOVE(AvahiLLMNREntryVerify, by_entry, ev->e->proto.llmnr.verifiers, ev); 177 178 avahi_free(ev); 179} 180 181static AvahiLLMNREntryVerify *get_verifier(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) { 182 AvahiLLMNREntryVerify *ev; 183 184 assert(s); 185 assert(i); 186 assert(e); 187 assert(e->type == AVAHI_ENTRY_LLMNR); 188 189 for (ev = e->proto.llmnr.verifiers; ev; ev = ev->by_entry_next) { 190 if (ev->interface == i) 191 return ev; 192 } 193 194 return NULL; 195} 196 197static void set_state(AvahiLLMNREntryVerify *ev) { 198 AvahiEntry *e; 199 assert(ev); 200 201 e = ev->e; 202 assert(e->type == AVAHI_ENTRY_LLMNR); 203 204 if ((e->flags & AVAHI_PUBLISH_UNIQUE) && !(e->flags & AVAHI_PUBLISH_NO_VERIFY)) 205 ev->state = AVAHI_VERIFYING; 206 else 207 ev->state = AVAHI_ESTABLISHED; 208 209 if (ev->state == AVAHI_VERIFYING) { 210 /* Structure to send in AvahiLLMNRQuery*/ 211 struct AvahiVerifierData *vdata; 212 213 vdata = avahi_new(AvahiVerifierData, 1); 214 /* Fill AvahiLLMNREntryVerify*/ 215 vdata->ev = ev; 216 217 /* Both these fields are filled by handle_response*/ 218 vdata->address = NULL; 219 220 /* If we get the response with t bit clear we don't touch this entry*/ 221 /* If we get the response with t bit set we set it so bt edfault keep it zero.*/ 222 vdata->t_bit = 0; 223 224 /* Initiate Query */ 225 ev->lq = avahi_llmnr_query_add(ev->interface, e->record->key, AVAHI_LLMNR_UNIQUENESS_VERIFICATION_QUERY, query_callback, vdata); 226 227 /* Increase n_verify */ 228 if (e->group) { 229 assert(e->group->type == AVAHI_GROUP_LLMNR); 230 e->group->proto.llmnr.n_verifying++; 231 } 232 233 } else { /*ev->state == AVAHI_ESTABLISHED */ 234 if (ev->e->group) 235 check_established(ev->e->group); 236 } 237} 238 239static void new_verifier(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) { 240 AvahiLLMNREntryVerify *ev; 241 242 assert(s); 243 assert(i); 244 assert(e); 245 assert(!e->dead); 246 assert(e->type == AVAHI_ENTRY_LLMNR); 247 248 if ( !avahi_interface_match (i, e->interface, e->protocol) || 249 !i->llmnr.verifying || 250 !avahi_entry_is_commited(e) ) 251 /* start verifying rr's only when group has been commited */ 252 return; 253 254 if (get_verifier(s, i, e)) 255 return; 256 257 if (!(ev = avahi_new(AvahiLLMNREntryVerify, 1))) 258 return; 259 260 ev->s= s; 261 ev->interface = i; 262 ev->e = e; 263 ev->lq = NULL; 264 265 AVAHI_LLIST_PREPEND(AvahiLLMNREntryVerify, by_interface, i->llmnr.verifiers, ev); 266 AVAHI_LLIST_PREPEND(AvahiLLMNREntryVerify, by_entry, e->proto.llmnr.verifiers, ev); 267 268 set_state(ev); 269} 270 271void avahi_verify_interface(AvahiServer *s, AvahiInterface *i) { 272 AvahiEntry *e; 273 274 assert(s); 275 assert(i); 276 277 if (!i->llmnr.verifying) 278 return; 279 280 for (e = s->llmnr.entries; e;e = e->entries_next) 281 if (!e->dead) 282 new_verifier(s, i, e); 283} 284 285static void verify_entry_walk_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, void * userdata) { 286 AvahiEntry *e = userdata; 287 288 assert(m); 289 assert(i); 290 assert(e); 291 assert(!e->dead); 292 293 new_verifier(m->server, i, e); 294} 295 296void avahi_verify_entry(AvahiServer *s, AvahiEntry *e) { 297 assert(s); 298 assert(e); 299 assert((!e->dead) && (e->type == AVAHI_ENTRY_LLMNR)); 300 301 avahi_interface_monitor_walk(s->monitor, e->interface, e->protocol, verify_entry_walk_callback, e); 302} 303 304void avahi_verify_group(AvahiServer *s, AvahiSEntryGroup *g) { 305 AvahiEntry *e; 306 307 assert(s); 308 assert(g); 309 assert(g->type == AVAHI_GROUP_LLMNR); 310 311 for (e = g->entries; e; e = e->by_group_next) { 312 if (!e->dead) 313 avahi_verify_entry(s, e); 314 } 315} 316 317int avahi_llmnr_entry_is_verifying(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) { 318 AvahiLLMNREntryVerify *ev; 319 320 assert(s); 321 assert(e); 322 assert(i); 323 assert((!e->dead) && (e->type == AVAHI_ENTRY_LLMNR)); 324 325 if ( !(ev = get_verifier(s, i, e)) || 326 (ev->state == AVAHI_CONFLICT)) 327 return -1; 328 329 if (ev->state == AVAHI_VERIFYING) 330 return 1; 331 332 assert(ev->state == AVAHI_VERIFIED); 333 334 return 0; 335} 336 337void avahi_llmnr_entry_return_to_initial_state(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) { 338 AvahiLLMNREntryVerify *ev; 339 340 assert(s); 341 assert(e); 342 assert(i); 343 assert((!e->dead) && (e->type == AVAHI_ENTRY_LLMNR)); 344 345 if (!(ev = get_verifier(s, i, e))) 346 return; 347 348 if (ev->state == AVAHI_VERIFYING) { 349 if (ev->e->group) { 350 avahi_llmnr_query_destroy(ev->lq); 351 ev->lq = NULL; 352 353 assert(ev->e->group->type == AVAHI_GROUP_LLMNR); 354 ev->e->group->proto.llmnr.n_verifying--; 355 } 356 } 357 358 set_state(ev); 359} 360 361static void avahi_reverify(AvahiLLMNREntryVerify *ev) { 362 AvahiEntry *e; 363 AvahiVerifierData *vdata; 364 365 assert(ev); 366 367 if (!(vdata = avahi_new(AvahiVerifierData, 1))) 368 return; 369 370 e = ev->e; 371 372 if (e->group) 373 assert(e->group->type == AVAHI_GROUP_LLMNR); 374 375 /* Group has not been commited yet, nothing to reverify*/ 376 if (e->group && (e->group->state = AVAHI_ENTRY_GROUP_LLMNR_UNCOMMITED || e->group->state == AVAHI_ENTRY_GROUP_LLMNR_COLLISION)) 377 return; 378 379 /* STATE == AVAHI_VERIFYING : Free the lq object and if entry belongs to 380 a group decrease the n_verifying counter. NEW STATE : _VERIFYING*/ 381 if (ev->state == AVAHI_VERIFYING) { 382 if (e->group) 383 e->group->proto.llmnr.n_verifying--; 384 385 } else if ((ev->state == AVAHI_LLMNR_ESTABLISHED) && (e->flags & AVAHI_PUBLISH_UNIQUE) && !(e->flags & AVAHI_PUBLISH_NO_VERIFY)) 386 /* _ESTABLISHED but _VERIFY again*/ 387 ev->state = AVAHI_VERIFYING; 388 389 else 390 ev->state = AVAHI_ESTABLISHED; 391 392 /* New state has been decided */ 393 394 if (ev->state == AVAHI_VERIFYING) { 395 396 vdata->ev = ev; 397 vdata->address = NULL; 398 vdata->t_bit = 0; 399 400 /* Start the queries */ 401 avahi_llmnr_query_add(ev->interface, e->record->key, AVAHI_LLMNR_UNIQUENESS_VERIFICATION_QUERY, query_callback, vdata); 402 403 /* Increase the counter if it belongs to a group */ 404 if (e->group) 405 e->group->proto.llmnr.n_verifying++; 406 407 } else 408 if (e->group) 409 check_established(e->group); 410} 411 412static void reannounce_walk_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, void* userdata) { 413 AvahiEntry *e = userdata; 414 AvahiLLMNREntryVerify *ev; 415 416 assert(m); 417 assert(i); 418 assert(e); 419 assert((!e->dead) && (e->type == AVAHI_ENTRY_LLMNR)); 420 421 if (!(ev = get_verifier(m->server, i, e))) 422 return; 423 424 avahi_reverify(ev); 425} 426 427void avahi_reverify_entry(AvahiServer *s, AvahiEntry *e) { 428 429 assert(s); 430 assert(e); 431 assert(!e->dead && e->type == AVAHI_ENTRY_LLMNR); 432 433 avahi_interface_monitor_walk(s->monitor, e->interface, e->protocol, reannounce_walk_callback, e); 434} 435 436void avahi_remove_verifiers(AvahiServer *s, AvahiEntry *e) { 437 assert(s); 438 assert(e); 439 assert(e->type == AVAHI_ENTRY_LLMNR); 440 441 while (e->proto.llmnr.verifiers) 442 remove_verifier(s, e->proto.llmnr.verifiers); 443} 444 445AvahiLLMNREntryVerifyState avahi_llmnr_entry_verify_state(AvahiLLMNREntryVerify *ev) { 446 assert(ev); 447 448 return (ev->state); 449} 450 451void avahi_remove_interface_verifiers(AvahiServer *s, AvahiInterface *i) { 452 assert(s); 453 assert(i); 454 455 while (i->llmnr.verifiers) 456 remove_verifier(s, i->llmnr.verifiers); 457} 458 459