]> git.meshlink.io Git - catta/blob - avahi-core/dns.c
* abstract MTU stuff for packet generation
[catta] / avahi-core / dns.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <netinet/in.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "dns.h"
33 #include "util.h"
34
35 AvahiDnsPacket* avahi_dns_packet_new(guint mtu) {
36     AvahiDnsPacket *p;
37     guint max_size;
38
39     if (mtu <= 0)
40         max_size = AVAHI_DNS_PACKET_MAX_SIZE;
41     else if (mtu >= 48)
42         max_size = mtu - 48;
43     else
44         max_size = 0;
45
46     if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
47         max_size = AVAHI_DNS_PACKET_HEADER_SIZE;
48     
49     p = g_malloc(sizeof(AvahiDnsPacket) + max_size);
50     p->size = p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
51     p->max_size = max_size;
52     p->name_table = NULL;
53
54     memset(AVAHI_DNS_PACKET_DATA(p), 0, p->size);
55     return p;
56 }
57
58 AvahiDnsPacket* avahi_dns_packet_new_query(guint mtu) {
59     AvahiDnsPacket *p;
60
61     p = avahi_dns_packet_new(mtu);
62     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
63     return p;
64 }
65
66 AvahiDnsPacket* avahi_dns_packet_new_response(guint mtu) {
67     AvahiDnsPacket *p;
68
69     p = avahi_dns_packet_new(mtu);
70     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
71     return p;
72 }
73
74 AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, guint mtu, gboolean copy_queries, gboolean aa) {
75     AvahiDnsPacket *r;
76     g_assert(p);
77
78     r = avahi_dns_packet_new_response(mtu);
79
80     if (copy_queries) {
81         guint n, saved_rindex;
82
83         saved_rindex = p->rindex;
84         p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
85         
86         for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) {
87             AvahiKey *k;
88             gboolean unicast_response;
89
90             if ((k = avahi_dns_packet_consume_key(p, &unicast_response))) {
91                 avahi_dns_packet_append_key(r, k, unicast_response);
92                 avahi_key_unref(k);
93             }
94         }
95
96         p->rindex = saved_rindex;
97
98         avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_QDCOUNT, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT));
99     }
100
101     avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID));
102
103     avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_FLAGS,
104                                (avahi_dns_packet_get_field(r, AVAHI_DNS_FIELD_FLAGS) & ~AVAHI_DNS_FLAG_OPCODE) |
105                                (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_OPCODE) |
106                                (aa ? AVAHI_DNS_FLAG_AA : 0));
107
108     return r;
109
110
111
112 void avahi_dns_packet_free(AvahiDnsPacket *p) {
113     g_assert(p);
114
115     if (p->name_table)
116         g_hash_table_destroy(p->name_table);
117     
118     g_free(p);
119 }
120
121 void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v) {
122     g_assert(p);
123     g_assert(index < AVAHI_DNS_PACKET_HEADER_SIZE);
124     
125     ((guint16*) AVAHI_DNS_PACKET_DATA(p))[index] = g_htons(v);
126 }
127
128 guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index) {
129     g_assert(p);
130     g_assert(index < AVAHI_DNS_PACKET_HEADER_SIZE);
131
132     return g_ntohs(((guint16*) AVAHI_DNS_PACKET_DATA(p))[index]);
133 }
134
135 /* Read the first label from string *name, unescape "\" and write it to dest */
136 gchar *avahi_unescape_label(gchar *dest, guint size, const gchar **name) {
137     guint i = 0;
138     gchar *d;
139     
140     g_assert(dest);
141     g_assert(size > 0);
142     g_assert(name);
143     g_assert(*name);
144
145     d = dest;
146     
147     for (;;) {
148         if (i >= size)
149             return NULL;
150
151         if (**name == '.') {
152             (*name)++;
153             break;
154         }
155         
156         if (**name == 0)
157             break;
158         
159         if (**name == '\\') {
160             (*name) ++;
161             
162             if (**name == 0)
163                 break;
164         }
165         
166         *(d++) = *((*name) ++);
167         i++;
168     }
169
170     g_assert(i < size);
171
172     *d = 0;
173
174     return dest;
175 }
176
177 guint8* avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name) {
178     guint8 *d, *saved_ptr = NULL;
179     guint saved_size;
180     
181     g_assert(p);
182     g_assert(name);
183
184     saved_size = p->size;
185     saved_ptr = avahi_dns_packet_extend(p, 0);
186     
187     while (*name) {
188         guint8* prev;
189         const gchar *pname;
190         gchar label[64];
191
192         /* Check whether we can compress this name. */
193
194         if (p->name_table && (prev = g_hash_table_lookup(p->name_table, name))) {
195             guint index;
196             
197             g_assert(prev >= AVAHI_DNS_PACKET_DATA(p));
198             index = (guint) (prev - AVAHI_DNS_PACKET_DATA(p));
199
200             g_assert(index < p->size);
201
202             if (index < 0x4000) {
203                 guint16 *t;
204                 if (!(t = (guint16*) avahi_dns_packet_extend(p, sizeof(guint16))))
205                     return NULL;
206
207                 *t = g_htons((0xC000 | index));
208                 return saved_ptr;
209             }
210         }
211
212         pname = name;
213         
214         if (!(avahi_unescape_label(label, sizeof(label), &name)))
215             goto fail;
216
217         if (!(d = avahi_dns_packet_append_string(p, label)))
218             goto fail;
219
220         if (!p->name_table)
221             p->name_table = g_hash_table_new_full((GHashFunc) avahi_domain_hash, (GEqualFunc) avahi_domain_equal, g_free, NULL);
222
223         g_hash_table_insert(p->name_table, g_strdup(pname), d);
224     }
225
226     if (!(d = avahi_dns_packet_extend(p, 1)))
227         goto fail;
228     
229     *d = 0;
230
231     return saved_ptr;
232
233 fail:
234     p->size = saved_size;
235     return NULL;
236 }
237
238 guint8* avahi_dns_packet_append_uint16(AvahiDnsPacket *p, guint16 v) {
239     guint8 *d;
240     g_assert(p);
241     
242     if (!(d = avahi_dns_packet_extend(p, sizeof(guint16))))
243         return NULL;
244     
245     *((guint16*) d) = g_htons(v);
246     return d;
247 }
248
249 guint8 *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, guint32 v) {
250     guint8 *d;
251     g_assert(p);
252
253     if (!(d = avahi_dns_packet_extend(p, sizeof(guint32))))
254         return NULL;
255     
256     *((guint32*) d) = g_htonl(v);
257
258     return d;
259 }
260
261 guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, gconstpointer b, guint l) {
262     guint8* d;
263
264     g_assert(p);
265     g_assert(b);
266     g_assert(l);
267
268     if (!(d = avahi_dns_packet_extend(p, l)))
269         return NULL;
270
271     memcpy(d, b, l);
272     return d;
273 }
274
275 guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s) {
276     guint8* d;
277     guint k;
278     
279     g_assert(p);
280     g_assert(s);
281
282     if ((k = strlen(s)) >= 255)
283         k = 255;
284     
285     if (!(d = avahi_dns_packet_extend(p, k+1)))
286         return NULL;
287
288     *d = (guint8) k;
289     memcpy(d+1, s, k);
290
291     return d;
292 }
293
294 guint8 *avahi_dns_packet_extend(AvahiDnsPacket *p, guint l) {
295     guint8 *d;
296     
297     g_assert(p);
298
299     if (p->size+l > p->max_size)
300         return NULL;
301     
302     d = AVAHI_DNS_PACKET_DATA(p) + p->size;
303     p->size += l;
304     
305     return d;
306 }
307
308 gint avahi_dns_packet_check_valid(AvahiDnsPacket *p) {
309     guint16 flags;
310     g_assert(p);
311
312     if (p->size < 12)
313         return -1;
314
315     flags = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS);
316
317     if (flags & AVAHI_DNS_FLAG_OPCODE || flags & AVAHI_DNS_FLAG_RCODE)
318         return -1;
319
320     return 0;
321 }
322
323 gint avahi_dns_packet_is_query(AvahiDnsPacket *p) {
324     g_assert(p);
325     
326     return !(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_QR);
327 }
328
329 /* Read a label from a DNS packet, escape "\" and ".", append \0 */
330 static gchar *escape_label(guint8* src, guint src_length, gchar **ret_name, guint *ret_name_length) {
331     gchar *r;
332
333     g_assert(src);
334     g_assert(ret_name);
335     g_assert(*ret_name);
336     g_assert(ret_name_length);
337     g_assert(*ret_name_length > 0);
338
339     r = *ret_name;
340
341     while (src_length > 0) {
342         if (*src == '.' || *src == '\\') {
343             if (*ret_name_length < 3)
344                 return NULL;
345             
346             *((*ret_name) ++) = '\\';
347             (*ret_name_length) --;
348         }
349
350         if (*ret_name_length < 2)
351             return NULL;
352         
353         *((*ret_name)++) = *src;
354         (*ret_name_length) --;
355
356         src_length --;
357         src++;
358     }
359
360     **ret_name = 0;
361
362     return r;
363 }
364
365 static gint consume_labels(AvahiDnsPacket *p, guint index, gchar *ret_name, guint l) {
366     gint ret = 0;
367     int compressed = 0;
368     int first_label = 1;
369     g_assert(p && ret_name && l);
370     
371     for (;;) {
372         guint8 n;
373
374         if (index+1 > p->size)
375             return -1;
376
377         n = AVAHI_DNS_PACKET_DATA(p)[index];
378
379         if (!n) {
380             index++;
381             if (!compressed)
382                 ret++;
383
384             if (l < 1)
385                 return -1;
386             *ret_name = 0;
387             
388             return ret;
389             
390         } else if (n <= 63) {
391             /* Uncompressed label */
392             index++;
393             if (!compressed)
394                 ret++;
395         
396             if (index + n > p->size)
397                 return -1;
398
399             if ((guint) n + 1 > l)
400                 return -1;
401
402             if (!first_label) {
403                 *(ret_name++) = '.';
404                 l--;
405             } else
406                 first_label = 0;
407
408             if (!(escape_label(AVAHI_DNS_PACKET_DATA(p) + index, n, &ret_name, &l)))
409                 return -1;
410
411             index += n;
412             
413             if (!compressed)
414                 ret += n;
415         } else if ((n & 0xC0) == 0xC0) {
416             /* Compressed label */
417
418             if (index+2 > p->size)
419                 return -1;
420
421             index = ((guint) (AVAHI_DNS_PACKET_DATA(p)[index] & ~0xC0)) << 8 | AVAHI_DNS_PACKET_DATA(p)[index+1];
422
423             if (!compressed)
424                 ret += 2;
425             
426             compressed = 1;
427         } else
428             return -1;
429     }
430 }
431
432 gint avahi_dns_packet_consume_name(AvahiDnsPacket *p, gchar *ret_name, guint l) {
433     gint r;
434     
435     if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
436         return -1;
437
438     p->rindex += r;
439     return 0;
440 }
441
442 gint avahi_dns_packet_consume_uint16(AvahiDnsPacket *p, guint16 *ret_v) {
443     g_assert(p);
444     g_assert(ret_v);
445
446     if (p->rindex + sizeof(guint16) > p->size)
447         return -1;
448
449     *ret_v = g_ntohs(*((guint16*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex)));
450     p->rindex += sizeof(guint16);
451
452     return 0;
453 }
454
455 gint avahi_dns_packet_consume_uint32(AvahiDnsPacket *p, guint32 *ret_v) {
456     g_assert(p);
457     g_assert(ret_v);
458
459     if (p->rindex + sizeof(guint32) > p->size)
460         return -1;
461
462     *ret_v = g_ntohl(*((guint32*) (AVAHI_DNS_PACKET_DATA(p) + p->rindex)));
463     p->rindex += sizeof(guint32);
464     
465     return 0;
466 }
467
468 gint avahi_dns_packet_consume_bytes(AvahiDnsPacket *p, gpointer ret_data, guint l) {
469     g_assert(p);
470     g_assert(ret_data);
471     g_assert(l > 0);
472     
473     if (p->rindex + l > p->size)
474         return -1;
475
476     memcpy(ret_data, AVAHI_DNS_PACKET_DATA(p) + p->rindex, l);
477     p->rindex += l;
478
479     return 0;
480 }
481
482 gint avahi_dns_packet_consume_string(AvahiDnsPacket *p, gchar *ret_string, guint l) {
483     guint k;
484     
485     g_assert(p);
486     g_assert(ret_string);
487     g_assert(l > 0);
488
489     if (p->rindex >= p->size)
490         return -1;
491
492     k = AVAHI_DNS_PACKET_DATA(p)[p->rindex];
493
494     if (p->rindex+1+k > p->size)
495         return -1;
496
497     if (l > k+1)
498         l = k+1;
499
500     memcpy(ret_string, AVAHI_DNS_PACKET_DATA(p)+p->rindex+1, l-1);
501     ret_string[l-1] = 0;
502
503     
504     p->rindex += 1+k;
505
506     return 0;
507     
508 }
509
510 gconstpointer avahi_dns_packet_get_rptr(AvahiDnsPacket *p) {
511     g_assert(p);
512     
513     if (p->rindex > p->size)
514         return NULL;
515
516     return AVAHI_DNS_PACKET_DATA(p) + p->rindex;
517 }
518
519 gint avahi_dns_packet_skip(AvahiDnsPacket *p, guint length) {
520     g_assert(p);
521
522     if (p->rindex + length > p->size)
523         return -1;
524
525     p->rindex += length;
526     return 0;
527 }
528
529 AvahiRecord* avahi_dns_packet_consume_record(AvahiDnsPacket *p, gboolean *ret_cache_flush) {
530     gchar name[257], buf[257];
531     guint16 type, class;
532     guint32 ttl;
533     guint16 rdlength;
534     AvahiRecord *r = NULL;
535     gconstpointer start;
536
537     g_assert(p);
538     g_assert(ret_cache_flush);
539
540 /*     g_message("consume_record()"); */
541
542     if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
543         avahi_dns_packet_consume_uint16(p, &type) < 0 ||
544         avahi_dns_packet_consume_uint16(p, &class) < 0 ||
545         avahi_dns_packet_consume_uint32(p, &ttl) < 0 ||
546         avahi_dns_packet_consume_uint16(p, &rdlength) < 0 ||
547         p->rindex + rdlength > p->size)
548         goto fail;
549
550 /*     g_message("name = %s, rdlength = %u", name, rdlength); */
551
552     *ret_cache_flush = !!(class & AVAHI_DNS_CACHE_FLUSH);
553     class &= ~AVAHI_DNS_CACHE_FLUSH;
554     
555     start = avahi_dns_packet_get_rptr(p);
556     
557     r = avahi_record_new_full(name, class, type);
558     
559     switch (type) {
560         case AVAHI_DNS_TYPE_PTR:
561         case AVAHI_DNS_TYPE_CNAME:
562
563 /*             g_message("ptr"); */
564             
565             if (avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
566                 goto fail;
567
568             r->data.ptr.name = g_strdup(buf);
569             break;
570
571             
572         case AVAHI_DNS_TYPE_SRV:
573
574 /*             g_message("srv"); */
575             
576             if (avahi_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 ||
577                 avahi_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 ||
578                 avahi_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 ||
579                 avahi_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
580                 goto fail;
581             
582             r->data.srv.name = g_strdup(buf);
583             break;
584
585         case AVAHI_DNS_TYPE_HINFO:
586             
587 /*             g_message("hinfo"); */
588
589             if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
590                 goto fail;
591
592             r->data.hinfo.cpu = g_strdup(buf);
593
594             if (avahi_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
595                 goto fail;
596
597             r->data.hinfo.os = g_strdup(buf);
598             break;
599
600         case AVAHI_DNS_TYPE_TXT:
601
602 /*             g_message("txt"); */
603
604             if (rdlength > 0) {
605                 r->data.txt.string_list = avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength);
606                 
607                 if (avahi_dns_packet_skip(p, rdlength) < 0)
608                     goto fail;
609             } else
610                 r->data.txt.string_list = NULL;
611             
612             break;
613
614         case AVAHI_DNS_TYPE_A:
615
616 /*             g_message("A"); */
617
618             if (avahi_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(AvahiIPv4Address)) < 0)
619                 goto fail;
620             
621             break;
622
623         case AVAHI_DNS_TYPE_AAAA:
624
625 /*             g_message("aaaa"); */
626             
627             if (avahi_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(AvahiIPv6Address)) < 0)
628                 goto fail;
629             
630             break;
631             
632         default:
633
634 /*             g_message("generic"); */
635             
636             if (rdlength > 0) {
637
638                 r->data.generic.data = g_memdup(avahi_dns_packet_get_rptr(p), rdlength);
639                 
640                 if (avahi_dns_packet_skip(p, rdlength) < 0)
641                     goto fail;
642             }
643
644             break;
645     }
646
647 /*     g_message("%i == %u ?", (guint8*) avahi_dns_packet_get_rptr(p) - (guint8*) start, rdlength); */
648     
649     /* Check if we read enough data */
650     if ((guint8*) avahi_dns_packet_get_rptr(p) - (guint8*) start != rdlength)
651         goto fail;
652     
653     r->ttl = ttl;
654
655     return r;
656
657 fail:
658     if (r)
659         avahi_record_unref(r);
660
661     return NULL;
662 }
663
664 AvahiKey* avahi_dns_packet_consume_key(AvahiDnsPacket *p, gboolean *ret_unicast_response) {
665     gchar name[256];
666     guint16 type, class;
667
668     g_assert(p);
669     g_assert(ret_unicast_response);
670
671     if (avahi_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
672         avahi_dns_packet_consume_uint16(p, &type) < 0 ||
673         avahi_dns_packet_consume_uint16(p, &class) < 0)
674         return NULL;
675
676     *ret_unicast_response = !!(class & AVAHI_DNS_UNICAST_RESPONSE);
677     class &= ~AVAHI_DNS_UNICAST_RESPONSE;
678
679     return avahi_key_new(name, class, type);
680 }
681
682 guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response) {
683     guint8 *t;
684     guint size;
685     
686     g_assert(p);
687     g_assert(k);
688
689     size = p->size;
690     
691     if (!(t = avahi_dns_packet_append_name(p, k->name)) ||
692         !avahi_dns_packet_append_uint16(p, k->type) ||
693         !avahi_dns_packet_append_uint16(p, k->class | (unicast_response ? AVAHI_DNS_UNICAST_RESPONSE : 0))) {
694         p->size = size;
695         return NULL;
696     }
697
698     return t;
699 }
700
701 guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush, guint max_ttl) {
702     guint8 *t, *l, *start;
703     guint size;
704
705     g_assert(p);
706     g_assert(r);
707
708     size = p->size;
709
710     if (!(t = avahi_dns_packet_append_name(p, r->key->name)) ||
711         !avahi_dns_packet_append_uint16(p, r->key->type) ||
712         !avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->class | AVAHI_DNS_CACHE_FLUSH) : (r->key->class &~ AVAHI_DNS_CACHE_FLUSH)) ||
713         !avahi_dns_packet_append_uint32(p, (max_ttl && r->ttl > max_ttl) ? max_ttl : r->ttl) ||
714         !(l = avahi_dns_packet_append_uint16(p, 0)))
715         goto fail;
716
717     start = avahi_dns_packet_extend(p, 0);
718
719     switch (r->key->type) {
720         
721         case AVAHI_DNS_TYPE_PTR:
722         case AVAHI_DNS_TYPE_CNAME :
723
724             if (!(avahi_dns_packet_append_name(p, r->data.ptr.name)))
725                 goto fail;
726             
727             break;
728
729         case AVAHI_DNS_TYPE_SRV:
730
731             if (!avahi_dns_packet_append_uint16(p, r->data.srv.priority) ||
732                 !avahi_dns_packet_append_uint16(p, r->data.srv.weight) ||
733                 !avahi_dns_packet_append_uint16(p, r->data.srv.port) ||
734                 !avahi_dns_packet_append_name(p, r->data.srv.name))
735                 goto fail;
736
737             break;
738
739         case AVAHI_DNS_TYPE_HINFO:
740             if (!avahi_dns_packet_append_string(p, r->data.hinfo.cpu) ||
741                 !avahi_dns_packet_append_string(p, r->data.hinfo.os))
742                 goto fail;
743
744             break;
745
746         case AVAHI_DNS_TYPE_TXT: {
747
748             guint8 *data;
749             guint size;
750
751             size = avahi_string_list_serialize(r->data.txt.string_list, NULL, 0);
752
753 /*             g_message("appending string: %u %p", size, r->data.txt.string_list); */
754
755             if (!(data = avahi_dns_packet_extend(p, size)))
756                 goto fail;
757
758             avahi_string_list_serialize(r->data.txt.string_list, data, size);
759             break;
760         }
761
762
763         case AVAHI_DNS_TYPE_A:
764
765             if (!avahi_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address)))
766                 goto fail;
767             
768             break;
769
770         case AVAHI_DNS_TYPE_AAAA:
771             
772             if (!avahi_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address)))
773                 goto fail;
774             
775             break;
776             
777         default:
778
779             if (r->data.generic.size &&
780                 avahi_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size))
781                 goto fail;
782
783             break;
784     }
785
786
787
788     
789     size = avahi_dns_packet_extend(p, 0) - start;
790     g_assert(size <= 0xFFFF);
791
792 /*     g_message("appended %u", size); */
793
794     * (guint16*) l = g_htons((guint16) size);
795     
796     return t;
797
798
799 fail:
800     p->size = size;
801     return NULL;
802 }
803
804 gboolean avahi_dns_packet_is_empty(AvahiDnsPacket *p) {
805     g_assert(p);
806
807     return p->size <= AVAHI_DNS_PACKET_HEADER_SIZE;
808 }
809
810 guint avahi_dns_packet_space(AvahiDnsPacket *p) {
811     g_assert(p);
812
813     g_assert(p->size <= p->max_size);
814     
815     return p->max_size - p->size;
816 }