]> git.karo-electronics.de Git - mdnsd.git/blob - rfc1035.c
Add futher files to .gitignore
[mdnsd.git] / rfc1035.c
1 /*
2  * Copyright (C) 2003 Jeremie Miller <jer@jabber.org>
3  * Copyright (c) 2009 Simon Budig <simon@budig.org>
4  * Copyright (C) 2013 Ole Reinhardt <ole.reinhardt@embedded-it.de>
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the copyright holders nor the names of
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * For additional information see http://www.ethernut.de/
35  */
36
37 /* This code is based on
38  * Based on BSD licensed mdnsd implementation by Jer <jer@jabber.org>
39  * http://dotlocal.org/mdnsd/
40  *
41  * Unfortunately this site is now longer alive. You can still find it at:
42  * http://web.archive.org/web/20080705131510/http://dotlocal.org/mdnsd/
43  *
44  * mdnsd - embeddable Multicast DNS Daemon
45  * =======================================
46  *
47  * "mdnsd" is a very lightweight, simple, portable, and easy to integrate
48  * open source implementation of Multicast DNS (part of Zeroconf, also called
49  * Rendezvous by Apple) for developers. It supports both acting as a Query and
50  * a Responder, allowing any software to participate fully on the .localnetwork
51  * just by including a few files and calling a few functions.  All of the
52  * complexity of handling the Multicast DNS retransmit timing, duplicate
53  * suppression, probing, conflict detection, and other facets of the DNS
54  * protocol is hidden behind a very simple and very easy to use interface,
55  * described in the header file. The single small c source file has almost no
56  * dependencies, and is portable to almost any embedded platform.
57  * Multiple example applications and usages are included in the download,
58  * including a simple persistent query browser and a tool to advertise .local
59  * web sites.
60  *
61  * The code is licensed under both the GPL and BSD licenses, for use in any
62  * free software or commercial application. If there is a licensing need not
63  * covered by either of those, alternative licensing is available upon request.
64  *
65  */
66
67 /*!
68  * \file pro/rfc1035.c
69  * \brief Standalone DNS parsing functions
70  *
71  * Implementation follows RF1035 [http://www.rfc-editor.org/rfc/rfc1035.txt] and
72  * includes decoding functions for svr rr's code type 33. See RFC2782
73  * [http://www.rfc-editor.org/rfc/rfc2782.txt]
74  *
75  * \verbatim
76  *
77  * $Id$
78  *
79  * \endverbatim
80  */
81
82 #include <string.h>
83 #include <stdio.h>
84 #include "rfc1035.h"
85
86 /*!
87  * \addtogroup xgMulticastDns
88  */
89 /*@{*/
90
91
92 /*!
93  * \brief Conversion of the network byte order buffer content into uint16_t value.
94  *
95  * This functions increments the buffer pointer accordingly
96  *
97  * \param buf   buffer
98  *
99  * \return      Converted value
100  */
101 uint16_t DnsNet2Short(uint8_t **buf)
102 {
103     uint16_t val;
104     val  = (*((*buf) ++)) << 8;
105     val |=  *((*buf) ++);
106     return val;
107 }
108
109
110 /*!
111  * \brief Conversion of the network byte order buffer content into uint32_t value.
112  *
113  * This functions increments the buffer pointer accordingly
114  *
115  * \param buf   buffer
116  *
117  * \return      Converted value
118  */
119 uint32_t DnsNet2Long(uint8_t **buf)
120 {
121     uint32_t val;
122     val  = (*((*buf) ++)) << 24;
123     val |= (*((*buf) ++)) << 16;
124     val |= (*((*buf) ++)) <<  8;
125     val |=  *((*buf) ++);
126     return val;
127 }
128
129
130 /*!
131  * \brief Conversion of uint16_t value into buffer content in network byte order
132  *
133  * This functions increments the buffer pointer accordingly
134  *
135  * \param val   Value
136  * \param buf   buffer
137  */
138 void DnsShort2Net(uint16_t val, uint8_t **buf)
139 {
140     *((*buf) ++) = (uint8_t) (val >> 8);
141     *((*buf) ++) = (uint8_t) val;
142 }
143
144 /*!
145  * \brief Conversion of uint32_t value into buffer content in network byte order
146  *
147  * This functions increments the buffer pointer accordingly
148  *
149  * \param val   Value
150  * \param buf   buffer
151  */
152 void DnsLong2Net(uint32_t val, uint8_t **buf)
153 {
154     *((*buf) ++) = (uint8_t) (val >> 24);
155     *((*buf) ++) = (uint8_t) (val >> 16);
156     *((*buf) ++) = (uint8_t) (val >> 8);
157     *((*buf) ++) = (uint8_t) val;
158 }
159
160
161 /*!
162  * \brief "Decompress" a label by calculating the offset of the original label string
163  *
164  * This functions increments the buffer pointer accordingly
165  *
166  * \param ptr   Pointer to the compressed label
167  *
168  * \return      Offset of the original label string
169  */
170 static uint16_t LabelDecompress(uint8_t *ptr)
171 {
172     uint16_t val;
173     val = 0xc0 ^ ptr[0];
174     val <<= 8;
175     val |= ptr[1];
176     if (val > PACKET_BUFFER_LEN - 1) {
177         val = PACKET_BUFFER_LEN - 1;
178     }
179     return val;
180 }
181
182
183 /*!
184  * \brief Extracts the label from the buffer.
185  *
186  * In case the label is compressed, it will be decompressed.
187  * This functions increments the buffer pointer accordingly.
188  * If the label is not yet cached, it will be added to the cached labels
189  *
190  * \param msg   DNS message
191  * \param buf   Pointer to the package data buffer
192  * \param namep Pointer to the string buffer, where the label will be copied to
193  */
194 static void ExtractLabel(DNSMESSAGE *msg, uint8_t **buf, char **namep)
195 {
196     uint8_t *label;
197     char *name;
198     int x;
199
200     /* Set the name pointer to the end of the data block */
201     name = msg->packet + msg->len;
202     *namep = name;
203
204     /* loop storing label in the block */
205     label = *buf;
206     while (*label != 0) {
207         /* Skip any compression pointer until end encountered */
208         while (*label & 0xc0) {
209             label = msg->buf + LabelDecompress(label);
210             if (*(label) == 0) {
211                 break;
212             }
213         }
214
215         /* Check the limits */
216         if (((name + *label) - *namep > 255) ||
217             (msg->len + ((name + *label) - *namep) > PACKET_BUFFER_LEN -1 )) {
218             return;
219         }
220
221         /* Copy label to the name buffer */
222         memcpy(name, label+1, *label);
223         name[*label] = '.';
224
225         name  += *label + 1;
226         label += *label + 1;
227     }
228
229     /* Advance in the buffer */
230     for (label = *buf; (*label != 0) && (!((*label & 0xc0) && label++)); label += *label + 1);
231     *buf = label + 1;
232
233     /* Add a traling \0 and check if the name is yet cached */
234     *name = '\0';
235
236     for (x = 0; x < MAX_LABEL; x++) {
237         if (msg->labels[x]) {
238             if (strcmp(*namep, msg->labels[x]) != 0) {
239                 continue;
240             }
241
242             *namep = msg->labels[x];
243             return;
244         }
245     }
246
247     /* The label was not yet cached, so cache it if there is still room */
248     if ((x < MAX_LABEL) && (msg->labels[x] == 0)) {
249         msg->labels[x] = *namep;
250     }
251     msg->len += (name - *namep) + 1;
252 }
253
254 /*!
255  * \brief Check if labels are matching
256  *
257  * If labels are compressed, they will be decompressed first.
258  *
259  * \param msg       DNS message
260  * \param label1    Pointer to label1
261  * \param label1    Pointer to label2
262  *
263  * \return          1 in case they are matching, else 0
264  */
265 static int MatchLabel(DNSMESSAGE *msg, uint8_t *label1, uint8_t *label2)
266 {
267     int len;
268
269     /* If we were calles with a pointer, call MatchLabel with dereferenced pointer again */
270     // TODO: Recursive
271     if (*label1 & 0xc0) {
272         return MatchLabel(msg, msg->buf + LabelDecompress(label1), label2);
273     }
274
275     if (*label2 & 0xc0) {
276         return MatchLabel(msg, label1, msg->buf + LabelDecompress(label2));
277     }
278
279     /* Return in case of a match */
280     if (label1 == label2) {
281         return 1;
282     }
283
284     /* Compare the label */
285     if (*label1 != *label2){
286         return 0;
287     }
288
289     for (len = 1; len <= *label1; len++) {
290         if (label1[len] != label2[len]) {
291             return 0;
292         }
293     }
294
295     /* Get the new labels */
296     label1 += *label1 + 1;
297     label2 += *label2 + 1;
298
299     /* Finally all labels should be matched */
300     if ((*label1 == 0) && (*label2 == 0)) {
301         return 1;
302     }
303
304     /* Recursivly call match with the next labels */
305     // TODO: Recursive
306     return MatchLabel(msg, label1, label2);
307 }
308
309
310 /*!
311  * \brief Convert host name to label using compression
312  *
313  * \param msg       DNS message
314  * \param buf       Pointer to the buffer where the label shall be placed
315  * \param name      Hostname
316  *
317  * \return          Length of the label
318  */
319 static int Host2Label(DNSMESSAGE *msg, uint8_t **buf, char *name)
320 {
321     uint8_t  label[MAX_LABEL_SIZE];
322     uint8_t *l;
323     int len = 0;
324     int x = 1;
325     int y = 0;
326     int last = 0;
327
328     if (name == NULL) {
329         return 0;
330     }
331
332     /* Let's make the label */
333     while(name[y]) {
334         if (name[y] == '.') {
335             if (name[y + 1] == 0) {
336                 break;
337             }
338             label[last] = x - (last + 1);
339             last = x;
340         } else {
341             label[x] = name[y];
342         }
343         if (x++ == MAX_LABEL_SIZE - 1) {
344             return 0;
345         }
346         y++;
347     }
348
349     label[last] = x - (last + 1);
350
351     if (x == 1) {
352         x--; // special case, bad names, but handle correctly
353     }
354     len = x + 1;
355
356     /* \0 terminate the label */
357     label[x] = 0;
358
359     /* Check each label against all msg->labels for a match */
360     for(x = 0; label[x]; x += label[x] + 1) {
361         for( y = 0; msg->labels[y]; y++) {
362             if (MatchLabel(msg, label+x, msg->labels[y])) {
363                 /* If the label matches, create the pointer */
364                 l = label + x;
365                 DnsShort2Net(msg->labels[y] - msg->packet, &l);
366                 label[x] |= 0xc0;
367                 len = x + 2;
368                 break;
369             }
370         }
371
372         if (label[x] & 0xc0) {
373             break;
374         }
375     }
376
377     /* Copy the label into the buffer and let the buffer pointer point to the label */
378     memcpy(*buf, label, len);
379     l = *buf;
380     *buf += len;
381
382     /* Save the label location of each new label for future compression */
383     for (x = 0; l[x]; x += l[x] + 1) {
384         if(l[x] & 0xc0) {
385             break;
386         }
387
388         if (msg->label + 1 >= MAX_LABEL - 1) {
389             break;
390         }
391
392         msg->labels[msg->label++] = l + x;
393     }
394
395     return len;
396 }
397
398
399 /*!
400  * \brief Parse a ressource record packet and fill the rr struct
401  *
402  * \param msg       DNS message
403  * \param rr        Pointer to ressource record struct where the informations shall be stored
404  * \param count     Number of ressource records in the package
405  * \param buf       Package buffer
406  *
407  * \return          0: success, -1 in case of an error
408  */
409 static int ParseRR(DNSMESSAGE *msg, DNSRESOURCE *rr, int count, uint8_t **buf)
410 {
411     int i;
412
413     for (i=0; i < count; i++) {
414         /* Extract the name, type, class, tt and record data length from the
415            buffer. The buffer pointer is automatically incremented by each call
416            tp nut2xxx
417          */
418         ExtractLabel(msg, buf, &(rr[i].name));
419         rr[i].type     = DnsNet2Short(buf);
420         rr[i].class    = DnsNet2Short(buf);
421         rr[i].ttl      = DnsNet2Long(buf);
422         rr[i].rdlength = DnsNet2Short(buf);
423
424         /* Sanity checking the length */
425         if ((rr[i].rdlength + (*buf - msg->buf) > MAX_PACKET_LEN) ||
426            (msg->len + rr[i].rdlength > MAX_PACKET_LEN)) {
427             return -1;
428         }
429
430         /* Length was ok, make a copy of the data */
431         rr[i].rdata = msg->packet + msg->len;
432
433         msg->len += rr[i].rdlength;
434         memcpy(rr[i].rdata, *buf, rr[i].rdlength);
435
436         /* Parse known message types */
437         switch (rr[i].type) {
438             case RRTYPE_A:
439                 if(msg->len + 16 > MAX_PACKET_LEN) {
440                     return -1;
441                 }
442                 rr[i].known.a.name = msg->packet + msg->len;
443                 msg->len += 16;
444                 sprintf(rr[i].known.a.name, "%d.%d.%d.%d", (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]);
445                 rr[i].known.a.ip = DnsNet2Long(buf);
446                 break;
447
448             case RRTYPE_NS:
449                 ExtractLabel(msg, buf, &(rr[i].known.ns.name));
450                 break;
451
452             case RRTYPE_CNAME:
453                 ExtractLabel(msg, buf, &(rr[i].known.cname.name));
454                 break;
455
456             case RRTYPE_PTR:
457                 ExtractLabel(msg, buf, &(rr[i].known.ptr.name));
458                 break;
459
460             case RRTYPE_SRV:
461                 rr[i].known.srv.priority = DnsNet2Short(buf);
462                 rr[i].known.srv.weight   = DnsNet2Short(buf);
463                 rr[i].known.srv.port     = DnsNet2Short(buf);
464                 ExtractLabel(msg, buf, &(rr[i].known.srv.name));
465                 break;
466
467             default:
468                 *buf += rr[i].rdlength;
469         }
470     }
471
472     return 0;
473 }
474
475
476 /*!
477  * \brief Parse DNS packet into message format
478  *
479  * The packet must be at least MAX_PACKET_LEN bytes in size and must be allocated clean (zeroed)
480  *
481  * \param msg       DNS message
482  * \param packet    Package buffer
483  */
484 void DnsParseMsg(DNSMESSAGE *msg, uint8_t *packet)
485 {
486     uint8_t *buf;
487     int i;
488
489     if((packet == 0) || (msg == 0)) {
490         return;
491     }
492
493     /* Bit decoding of the record header */
494     buf = packet;
495     msg->buf = buf;
496     msg->id = DnsNet2Short(&buf);
497 // TODO: Ohne shiften auf die Bits prüfen, korrekte Bitwerte hinterlegen
498
499     if (buf[0] & 0x80) {
500         msg->header.qr = 1;
501     }
502
503     /* Shift opcode field 3 bits right for easy comparision */
504     msg->header.opcode = (buf[0] & 0x78) >> 3;
505
506     if (buf[0] & 0x01) {
507         msg->header.rd = 1;
508     }
509
510     if (buf[0] & 0x02) {
511         msg->header.tc = 1;
512     }
513
514     if (buf[0] & 0x04) {
515         msg->header.aa = 1;
516     }
517
518     if (buf[1] & 0x80) {
519         msg->header.ra = 1;
520     }
521
522     msg->header.z = (buf[1] & 0x70) >> 4;
523     msg->header.rcode = buf[1] & 0x0F;
524     buf += 2;
525
526     msg->qdcount = DnsNet2Short(&buf);
527     if (msg->len + (sizeof(DNSQUESTION) * msg->qdcount) > MAX_PACKET_LEN - 8) {
528         msg->qdcount = 0;
529         return;
530     }
531
532     /* Get number of AN records */
533     msg->ancount = DnsNet2Short(&buf);
534     if (msg->len + (sizeof(DNSRESOURCE) * msg->ancount) > MAX_PACKET_LEN - 8) {
535         msg->ancount = 0;
536         return;
537     }
538
539     /* Get number of NS records */
540     msg->nscount = DnsNet2Short(&buf);
541     if (msg->len + (sizeof(DNSRESOURCE) * msg->nscount) > MAX_PACKET_LEN - 8) {
542         msg->nscount = 0;
543         return;
544     }
545
546     /* Get number of AR records */
547     msg->arcount = DnsNet2Short(&buf);
548     if (msg->len + (sizeof(DNSRESOURCE) * msg->arcount) > MAX_PACKET_LEN - 8) {
549         msg->arcount = 0;
550         return;
551     }
552
553     /* Process the questions */
554     while (msg->len & 0x07) msg->len++;
555     /* Process AN record */
556     msg->qd= (DNSQUESTION *) (msg->packet + msg->len);
557     msg->len += sizeof(DNSQUESTION) * msg->qdcount;
558
559     for(i = 0; i < msg->qdcount; i++) {
560         ExtractLabel(msg, &buf, &(msg->qd[i].name));
561         msg->qd[i].type  = DnsNet2Short(&buf);
562         msg->qd[i].class = DnsNet2Short(&buf);
563     }
564
565
566     /* Process Ressource records and keep us always at a 8 byte boundary */
567
568     /* Align... */
569     while (msg->len & 0x07) msg->len++;
570     /* Process AN record */
571     msg->an = (DNSRESOURCE *) (msg->packet + msg->len);
572     msg->len += sizeof(DNSRESOURCE) * msg->ancount;
573
574     /* Align... */
575     while (msg->len & 0x07) msg->len++;
576     /* Process NS record */
577     msg->ns = (DNSRESOURCE *) (msg->packet + msg->len);
578     msg->len += sizeof(DNSRESOURCE) * msg->nscount;
579
580     /* Align... */
581     while (msg->len & 0x07) msg->len++;
582     /* Process AR record */
583     msg->ar = (DNSRESOURCE *) (msg->packet + msg->len);
584     msg->len += sizeof(DNSRESOURCE) * msg->arcount;
585
586     /* Parse AN record */
587     if (ParseRR(msg, msg->an, msg->ancount, &buf)) {
588         /* Size limit checking failed */
589         return;
590     }
591
592     /* Parse NS record */
593     if (ParseRR(msg, msg->ns, msg->nscount, &buf)) {
594         /* Size limit checking failed */
595         return;
596     }
597
598     /* Parse AR record */
599     if (ParseRR(msg, msg->ar, msg->arcount, &buf)) {
600         /* Size limit checking failed */
601         return;
602     }
603 }
604
605
606 /*!
607  * \brief Append a ressource record to the message
608  *
609  * \param msg       DNS message
610  * \param name      Hostname
611  * \param type      Query type
612  * \param class     Query class
613  * \param ttl       TTL value
614  */
615 static void DnsAppendRR(DNSMESSAGE *msg, char *name, uint16_t type, uint16_t class, uint32_t ttl)
616 {
617     if (msg->buf == 0) {
618         /* Initialise the buffer pointer */
619         msg->buf = msg->packet + 12;
620     }
621     Host2Label(msg, &(msg->buf), name);
622     DnsShort2Net(type, &(msg->buf));
623     DnsShort2Net(class, &(msg->buf));
624     DnsLong2Net(ttl, &(msg->buf));
625 }
626
627
628 /*!
629  * \brief Append a QD ressource record to the message
630  *
631  * Should be called first before calling DnsMsgAdd_an.
632  *
633  * \param msg       DNS message
634  * \param name      Hostname
635  * \param type      Query type
636  * \param class     Query class
637  */
638 void DnsMsgAdd_qd(DNSMESSAGE *msg, char *name, uint16_t type, uint16_t class)
639 {
640     msg->qdcount++;
641     if (msg->buf == 0) {
642         /* Initialise the buffer pointer */
643         msg->buf = msg->packet + 12;
644     }
645
646     Host2Label(msg, &(msg->buf), name);
647     DnsShort2Net(type, &(msg->buf));
648     DnsShort2Net(class, &(msg->buf));
649 }
650
651
652 /*!
653  * \brief Append a AN ressource record to the message
654  *
655  * Should be called first before calling DnsMsgAdd_ns.
656  *
657  * \param msg       DNS message
658  * \param name      Hostname
659  * \param type      Query type
660  * \param class     Query class
661  */
662 void DnsMsgAdd_an(DNSMESSAGE *msg, char *name, uint16_t type, uint16_t class, uint32_t ttl)
663 {
664     msg->ancount++;
665     DnsAppendRR(msg, name, type, class, ttl);
666 }
667
668
669 /*!
670  * \brief Append a NS ressource record to the message
671  *
672  * Should be called first before calling DnsMsgAdd_ar.
673  *
674  * \param msg       DNS message
675  * \param name      Hostname
676  * \param type      Query type
677  * \param class     Query class
678  */
679 void DnsMsgAdd_ns(DNSMESSAGE *msg, char *name, uint16_t type, uint16_t class, uint32_t ttl)
680 {
681     msg->nscount++;
682     DnsAppendRR(msg, name, type, class, ttl);
683 }
684
685
686 /*!
687  * \brief Append a AR ressource record to the message
688  *
689  * \param msg       DNS message
690  * \param name      Hostname
691  * \param type      Query type
692  * \param class     Query class
693  */
694 void DnsMsgAdd_ar(DNSMESSAGE *msg, char *name, uint16_t type, uint16_t class, uint32_t ttl)
695 {
696     msg->arcount++;
697     DnsAppendRR(msg, name, type, class, ttl);
698 }
699
700
701 /*!
702  * \brief Append resource data types block: uint32_t value
703  *
704  * \param msg       DNS message
705  * \param val       value
706  */
707 void DnsMsgAdd_rdata_long(DNSMESSAGE *msg, uint32_t val)
708 {
709     DnsShort2Net(4, &(msg->buf));
710     DnsLong2Net(val, &(msg->buf));
711 }
712
713
714 /*!
715  * \brief Append resource data types block: Hostname
716  *
717  * \param msg       DNS message
718  * \param name      Hostname
719  */
720 void DnsMsgAdd_rdata_name(DNSMESSAGE *msg, char *name)
721 {
722     uint8_t *tmp_buf = msg->buf;
723     msg->buf += 2;
724     DnsShort2Net(Host2Label(msg, &(msg->buf), name), &tmp_buf);
725 }
726
727 /*!
728  * \brief Append resource data types block: Service data
729  *
730  * \param msg       DNS message
731  * \param priority  Priority of the target host: lower value means more preferred.
732  * \param weight    Relative weight for records with the same priority.
733  * \param port      TCP / UDP port number of the service
734  * \param name      The canonical hostname of the machine providing the service.
735  */
736 void DnsMsgAdd_rdata_srv(DNSMESSAGE *msg, uint16_t priority, uint16_t weight, uint16_t port, char *name)
737 {
738     uint8_t *tmp_buf = msg->buf;
739     msg->buf += 2;
740     DnsShort2Net(priority, &(msg->buf));
741     DnsShort2Net(weight, &(msg->buf));
742     DnsShort2Net(port, &(msg->buf));
743     DnsShort2Net(Host2Label(msg, &(msg->buf), name) + 6, &tmp_buf);
744 }
745
746
747 /*!
748  * \brief Append resource data types block: Raw data
749  *
750  * \param msg       DNS message
751  * \param rdata     Pointer to the raw data buffer
752  * \param rdlength  Length of the raw data block
753  */
754 void DnsMsgAdd_rdata_raw(DNSMESSAGE *msg, uint8_t *rdata, uint16_t rdlength)
755 {
756     if ((msg->buf - msg->packet) + rdlength > MAX_PACKET_LEN) {
757         rdlength = 0;
758     }
759     DnsShort2Net(rdlength, &(msg->buf));
760     memcpy(msg->buf, rdata, rdlength);
761     msg->buf += rdlength;
762 }
763
764
765 /*!
766  * \brief Generate the message packet to be send out.
767  *
768  * \return      Packet buffer
769  */
770 uint8_t *DnsMsg2Pkt(DNSMESSAGE *msg)
771 {
772     uint8_t c, *buf = msg->buf;
773     msg->buf = msg->packet;
774     DnsShort2Net(msg->id, &(msg->buf));
775 // TODO: Bits direkt ohne shiften
776     if (msg->header.qr) {
777         msg->buf[0] |= 0x80;
778     }
779
780     if ((c = msg->header.opcode)) {
781         msg->buf[0] |= (c << 3);
782     }
783     if (msg->header.aa) {
784         msg->buf[0] |= 0x04;
785     }
786
787     if (msg->header.tc) {
788         msg->buf[0] |= 0x02;
789     }
790
791     if (msg->header.rd) {
792         msg->buf[0] |= 0x01;
793     }
794
795     if (msg->header.ra) {
796         msg->buf[1] |= 0x80;
797     }
798
799     if ((c = msg->header.z)) {
800         msg->buf[1] |= (c << 4);
801     }
802
803     if (msg->header.rcode) {
804         msg->buf[1] |= msg->header.rcode;
805     }
806
807     msg->buf += 2;
808
809     DnsShort2Net(msg->qdcount, &(msg->buf));
810     DnsShort2Net(msg->ancount, &(msg->buf));
811     DnsShort2Net(msg->nscount, &(msg->buf));
812     DnsShort2Net(msg->arcount, &(msg->buf));
813
814     /* Restore the packet pointer. It is necessary for DnsMsgLen() */
815     msg->buf = buf;
816
817     /* Return the modified packet */
818     return msg->packet;
819 }
820
821
822 /*!
823  * \brief Calculate message packet length
824  *
825  * \return      Message packet length
826  */
827
828 int DnsMsgLen(DNSMESSAGE *msg)
829 {
830     if(msg->buf == 0) return 12;
831     return msg->buf - msg->packet;
832 }
833
834 /*@}*/