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