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