-#include <string.h>
-#include <stdio.h>
-#include "1035.h"
-
-unsigned short int net2short(unsigned char **bufp)
+/*
+ * Copyright (C) 2003 Jeremie Miller <jer@jabber.org>
+ * Copyright (c) 2009 Simon Budig <simon@budig.org>
+ * Copyright (C) 2013 Ole Reinhardt <ole.reinhardt@embedded-it.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * For additional information see http://www.ethernut.de/
+ */
+
+/* This code is based on
+ * Based on BSD licensed mdnsd implementation by Jer <jer@jabber.org>
+ * http://dotlocal.org/mdnsd/
+ *
+ * Unfortunately this site is now longer alive. You can still find it at:
+ * http://web.archive.org/web/20080705131510/http://dotlocal.org/mdnsd/
+ *
+ * mdnsd - embeddable Multicast DNS Daemon
+ * =======================================
+ *
+ * "mdnsd" is a very lightweight, simple, portable, and easy to integrate
+ * open source implementation of Multicast DNS (part of Zeroconf, also called
+ * Rendezvous by Apple) for developers. It supports both acting as a Query and
+ * a Responder, allowing any software to participate fully on the .localnetwork
+ * just by including a few files and calling a few functions. All of the
+ * complexity of handling the Multicast DNS retransmit timing, duplicate
+ * suppression, probing, conflict detection, and other facets of the DNS
+ * protocol is hidden behind a very simple and very easy to use interface,
+ * described in the header file. The single small c source file has almost no
+ * dependencies, and is portable to almost any embedded platform.
+ * Multiple example applications and usages are included in the download,
+ * including a simple persistent query browser and a tool to advertise .local
+ * web sites.
+ *
+ * The code is licensed under both the GPL and BSD licenses, for use in any
+ * free software or commercial application. If there is a licensing need not
+ * covered by either of those, alternative licensing is available upon request.
+ *
+ */
+
+/*!
+ * \file pro/rfc1035.c
+ * \brief Standalone DNS parsing functions
+ *
+ * Implementation follows RF1035 [http://www.rfc-editor.org/rfc/rfc1035.txt] and
+ * includes decoding functions for svr rr's code type 33. See RFC2782
+ * [http://www.rfc-editor.org/rfc/rfc2782.txt]
+ *
+ * \verbatim
+ *
+ * $Id$
+ *
+ * \endverbatim
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "rfc1035.h"
+
+/*!
+ * \addtogroup xgMulticastDns
+ */
+/*@{*/
+
+
+/*!
+ * \brief Conversion of the network byte order buffer content into uint16_t value.
+ *
+ * This functions increments the buffer pointer accordingly
+ *
+ * \param buf buffer
+ *
+ * \return Converted value
+ */
+uint16_t DnsNet2Short(uint8_t **buf)
{
- short int i;
- i = **bufp;
- i <<= 8;
- i |= *(*bufp + 1);
- *bufp += 2;
- return i;
+ uint16_t val;
+ val = (*((*buf) ++)) << 8;
+ val |= *((*buf) ++);
+ return val;
}
-unsigned long int net2long(unsigned char **bufp)
+
+/*!
+ * \brief Conversion of the network byte order buffer content into uint32_t value.
+ *
+ * This functions increments the buffer pointer accordingly
+ *
+ * \param buf buffer
+ *
+ * \return Converted value
+ */
+uint32_t DnsNet2Long(uint8_t **buf)
{
- long int l;
- l = **bufp;
- l <<= 8;
- l |= *(*bufp + 1);
- l <<= 8;
- l |= *(*bufp + 2);
- l <<= 8;
- l |= *(*bufp + 3);
- *bufp += 4;
- return l;
+ uint32_t val;
+ val = (*((*buf) ++)) << 24;
+ val |= (*((*buf) ++)) << 16;
+ val |= (*((*buf) ++)) << 8;
+ val |= *((*buf) ++);
+ return val;
}
-void short2net(unsigned short int i, unsigned char **bufp)
+
+/*!
+ * \brief Conversion of uint16_t value into buffer content in network byte order
+ *
+ * This functions increments the buffer pointer accordingly
+ *
+ * \param val Value
+ * \param buf buffer
+ */
+void DnsShort2Net(uint16_t val, uint8_t **buf)
{
- *(*bufp + 1) = (unsigned char)i;
- i >>= 8;
- **bufp = (unsigned char)i;
- *bufp += 2;
+ *((*buf) ++) = (uint8_t) (val >> 8);
+ *((*buf) ++) = (uint8_t) val;
}
-void long2net(unsigned long int l, unsigned char **bufp)
+/*!
+ * \brief Conversion of uint32_t value into buffer content in network byte order
+ *
+ * This functions increments the buffer pointer accordingly
+ *
+ * \param val Value
+ * \param buf buffer
+ */
+void DnsLong2Net(uint32_t val, uint8_t **buf)
{
- *(*bufp + 3) = (unsigned char)l;
- l >>= 8;
- *(*bufp + 2) = (unsigned char)l;
- l >>= 8;
- *(*bufp + 1) = (unsigned char)l;
- l >>= 8;
- **bufp = (unsigned char)l;
- *bufp += 4;
+ *((*buf) ++) = (uint8_t) (val >> 24);
+ *((*buf) ++) = (uint8_t) (val >> 16);
+ *((*buf) ++) = (uint8_t) (val >> 8);
+ *((*buf) ++) = (uint8_t) val;
}
-unsigned short int _ldecomp(unsigned char *ptr)
+
+/*!
+ * \brief "Decompress" a label by calculating the offset of the original label string
+ *
+ * This functions increments the buffer pointer accordingly
+ *
+ * \param ptr Pointer to the compressed label
+ *
+ * \return Offset of the original label string
+ */
+static uint16_t LabelDecompress(uint8_t *ptr)
{
- unsigned short int i;
- i = 0xc0 ^ ptr[0];
- i <<= 8;
- i |= ptr[1];
- if(i >= 4096) i = 4095;
- return i;
+ uint16_t val;
+ val = 0xc0 ^ ptr[0];
+ val <<= 8;
+ val |= ptr[1];
+ if (val > PACKET_BUFFER_LEN - 1) {
+ val = PACKET_BUFFER_LEN - 1;
+ }
+ return val;
}
-void _label(struct message *m, unsigned char **bufp, unsigned char **namep)
+
+/*!
+ * \brief Extracts the label from the buffer.
+ *
+ * In case the label is compressed, it will be decompressed.
+ * This functions increments the buffer pointer accordingly.
+ * If the label is not yet cached, it will be added to the cached labels
+ *
+ * \param msg DNS message
+ * \param buf Pointer to the package data buffer
+ * \param namep Pointer to the string buffer, where the label will be copied to
+ */
+static void ExtractLabel(DNSMESSAGE *msg, uint8_t **buf, uint8_t **namep)
{
- unsigned char *label, *name;
+ uint8_t *label;
+ uint8_t *name;
int x;
- // set namep to the end of the block
- *namep = name = m->_packet + m->_len;
-
- // loop storing label in the block
- for(label = *bufp; *label != 0; name += *label + 1, label += *label + 1)
- {
- // skip past any compression pointers, kick out if end encountered (bad data prolly)
- while(*label & 0xc0)
- if(*(label = m->_buf + _ldecomp(label)) == 0) break;
+ /* Set the name pointer to the end of the data block */
+ name = msg->packet + msg->len;
+ *namep = name;
+
+ /* loop storing label in the block */
+ label = *buf;
+ while (*label != 0) {
+ /* Skip any compression pointer until end encountered */
+ while (*label & 0xc0) {
+ label = msg->buf + LabelDecompress(label);
+ if (*(label) == 0) {
+ break;
+ }
+ }
- // make sure we're not over the limits
- if((name + *label) - *namep > 255 || m->_len + ((name + *label) - *namep) > 4096) return;
+ /* Check the limits */
+ if (((name + *label) - *namep > 255) ||
+ (msg->len + ((name + *label) - *namep) > PACKET_BUFFER_LEN -1 )) {
+ return;
+ }
- // copy chars for this label
- memcpy(name,label+1,*label);
+ /* Copy label to the name buffer */
+ memcpy(name, label+1,*label);
name[*label] = '.';
- }
- // advance buffer
- for(label = *bufp; *label != 0 && !(*label & 0xc0 && label++); label += *label + 1);
- *bufp = label + 1;
+ name += *label + 1;
+ label += *label + 1;
+ }
+
+ /* Advance in the buffer */
+ for (label = *buf; (*label != 0) && (!((*label & 0xc0) && label++)); label += *label + 1);
+ *buf = label + 1;
- // terminate name and check for cache or cache it
+ /* Add a traling \0 and check if the name is yet cached */
*name = '\0';
- for(x = 0; x <= 19 && m->_labels[x]; x++)
- {
- if(strcmp(*namep,m->_labels[x])) continue;
- *namep = m->_labels[x];
- return;
+
+ for (x = 0; x < MAX_LABEL; x++) {
+ if (msg->labels[x]) {
+ if (strcmp(*namep, msg->labels[x]) != 0) {
+ continue;
+ }
+
+ *namep = msg->labels[x];
+ return;
+ }
+ }
+
+ /* The label was not yet cached, so cache it if there is still room */
+ if ((x < MAX_LABEL) && (msg->labels[x] == 0)) {
+ msg->labels[x] = *namep;
}
- // no cache, so cache it if room
- if(x <= 19 && m->_labels[x] == 0)
- m->_labels[x] = *namep;
- m->_len += (name - *namep) + 1;
+ msg->len += (name - *namep) + 1;
}
-// internal label matching
-int _lmatch(struct message *m, unsigned char *l1, unsigned char *l2)
+/*!
+ * \brief Check if labels are matching
+ *
+ * If labels are compressed, they will be decompressed first.
+ *
+ * \param msg DNS message
+ * \param label1 Pointer to label1
+ * \param label1 Pointer to label2
+ *
+ * \return 1 in case they are matching, else 0
+ */
+static int MatchLabel(DNSMESSAGE *msg, uint8_t *label1, uint8_t *label2)
{
int len;
- // always ensure we get called w/o a pointer
- if(*l1 & 0xc0) return _lmatch(m, m->_buf + _ldecomp(l1),l2);
- if(*l2 & 0xc0) return _lmatch(m, l1, m->_buf + _ldecomp(l2));
-
- // same already?
- if(l1 == l2) return 1;
-
- // compare all label characters
- if(*l1 != *l2) return 0;
- for(len = 1; len <= *l1; len++)
- if(l1[len] != l2[len]) return 0;
-
- // get new labels
- l1 += *l1 + 1;
- l2 += *l2 + 1;
-
- // at the end, all matched
- if(*l1 == 0 && *l2 == 0) return 1;
-
- // try next labels
- return _lmatch(m,l1,l2);
+ /* If we were calles with a pointer, call MatchLabel with dereferenced pointer again */
+ // TODO: Recursive
+ if (*label1 & 0xc0) {
+ return MatchLabel(msg, msg->buf + LabelDecompress(label1), label2);
+ }
+
+ if (*label2 & 0xc0) {
+ return MatchLabel(msg, label1, msg->buf + LabelDecompress(label2));
+ }
+
+ /* Return in case of a match */
+ if (label1 == label2) {
+ return 1;
+ }
+
+ /* Compare the label */
+ if (*label1 != *label2){
+ return 0;
+ }
+
+ for (len = 1; len <= *label1; len++) {
+ if (label1[len] != label2[len]) {
+ return 0;
+ }
+ }
+
+ /* Get the new labels */
+ label1 += *label1 + 1;
+ label2 += *label2 + 1;
+
+ /* Finally all labels should be matched */
+ if ((*label1 == 0) && (*label2 == 0)) {
+ return 1;
+ }
+
+ /* Recursivly call match with the next labels */
+ // TODO: Recursive
+ return MatchLabel(msg, label1, label2);
}
-// nasty, convert host into label using compression
-int _host(struct message *m, unsigned char **bufp, unsigned char *name)
-{
- unsigned char label[256], *l;
- int len = 0, x = 1, y = 0, last = 0;
- if(name == 0) return 0;
+/*!
+ * \brief Convert host name to label using compression
+ *
+ * \param msg DNS message
+ * \param buf Pointer to the buffer where the label shall be placed
+ * \param name Hostname
+ *
+ * \return Length of the label
+ */
+static int Host2Label(DNSMESSAGE *msg, uint8_t **buf, uint8_t *name)
+{
+ uint8_t label[MAX_LABEL_SIZE];
+ uint8_t *l;
+ int len = 0;
+ int x = 1;
+ int y = 0;
+ int last = 0;
+
+ if (name == NULL) {
+ return 0;
+ }
- // make our label
- while(name[y])
- {
- if(name[y] == '.')
- {
- if(!name[y+1]) break;
+ /* Let's make the label */
+ while(name[y]) {
+ if (name[y] == '.') {
+ if (name[y + 1] == 0) {
+ break;
+ }
label[last] = x - (last + 1);
last = x;
- }else{
+ } else {
label[x] = name[y];
}
- if(x++ == 255) return 0;
+ if (x++ == MAX_LABEL_SIZE - 1) {
+ return 0;
+ }
y++;
}
+
label[last] = x - (last + 1);
- if(x == 1) x--; // special case, bad names, but handle correctly
+
+ if (x == 1) {
+ x--; // special case, bad names, but handle correctly
+ }
len = x + 1;
- label[x] = 0; // always terminate w/ a 0
-
- // double-loop checking each label against all m->_labels for match
- for(x = 0; label[x]; x += label[x] + 1)
- {
- for(y = 0; m->_labels[y]; y++)
- if(_lmatch(m,label+x,m->_labels[y]))
- {
- // matching label, set up pointer
+
+ /* \0 terminate the label */
+ label[x] = 0;
+
+ /* Check each label against all msg->labels for a match */
+ for(x = 0; label[x]; x += label[x] + 1) {
+ for( y = 0; msg->labels[y]; y++) {
+ if (MatchLabel(msg, label+x, msg->labels[y])) {
+ /* If the label matches, create the pointer */
l = label + x;
- short2net(m->_labels[y] - m->_packet, &l);
+ DnsShort2Net(msg->labels[y] - msg->packet, &l);
label[x] |= 0xc0;
len = x + 2;
break;
}
- if(label[x] & 0xc0) break;
+ }
+
+ if (label[x] & 0xc0) {
+ break;
+ }
}
- // copy into buffer, point there now
- memcpy(*bufp,label,len);
- l = *bufp;
- *bufp += len;
+ /* Copy the label into the buffer and let the buffer pointer point to the label */
+ memcpy(*buf, label, len);
+ l = *buf;
+ *buf += len;
- // for each new label, store it's location for future compression
- for(x = 0; l[x]; x += l[x] + 1)
- {
- if(l[x] & 0xc0) break;
- if(m->_label + 1 >= 19) break;
- m->_labels[m->_label++] = l + x;
+ /* Save the label location of each new label for future compression */
+ for (x = 0; l[x]; x += l[x] + 1) {
+ if(l[x] & 0xc0) {
+ break;
+ }
+
+ if (msg->label + 1 >= MAX_LABEL - 1) {
+ break;
+ }
+
+ msg->labels[msg->label++] = l + x;
}
return len;
}
-int _rrparse(struct message *m, struct resource *rr, int count, unsigned char **bufp)
+
+/*!
+ * \brief Parse a ressource record packet and fill the rr struct
+ *
+ * \param msg DNS message
+ * \param rr Pointer to ressource record struct where the informations shall be stored
+ * \param count Number of ressource records in the package
+ * \param buf Package buffer
+ *
+ * \return 0: success, -1 in case of an error
+ */
+static int ParseRR(DNSMESSAGE *msg, DNSRESOURCE *rr, int count, uint8_t **buf)
{
int i;
- for(i=0; i < count; i++)
- {
- _label(m, bufp, &(rr[i].name));
- rr[i].type = net2short(bufp);
- rr[i].class = net2short(bufp);
- rr[i].ttl = net2long(bufp);
- rr[i].rdlength = net2short(bufp);
-
- // if not going to overflow, make copy of source rdata
- if(rr[i].rdlength + (*bufp - m->_buf) > MAX_PACKET_LEN || m->_len + rr[i].rdlength > MAX_PACKET_LEN) return 1;
- rr[i].rdata = m->_packet + m->_len;
- m->_len += rr[i].rdlength;
- memcpy(rr[i].rdata,*bufp,rr[i].rdlength);
-
- // parse commonly known ones
- switch(rr[i].type)
- {
- case 1:
- if(m->_len + 16 > MAX_PACKET_LEN) return 1;
- rr[i].known.a.name = m->_packet + m->_len;
- m->_len += 16;
- sprintf(rr[i].known.a.name,"%d.%d.%d.%d",(*bufp)[0],(*bufp)[1],(*bufp)[2],(*bufp)[3]);
- rr[i].known.a.ip = net2long(bufp);
- break;
- case 2:
- _label(m, bufp, &(rr[i].known.ns.name));
- break;
- case 5:
- _label(m, bufp, &(rr[i].known.cname.name));
- break;
- case 12:
- _label(m, bufp, &(rr[i].known.ptr.name));
- break;
- case 33:
- rr[i].known.srv.priority = net2short(bufp);
- rr[i].known.srv.weight = net2short(bufp);
- rr[i].known.srv.port = net2short(bufp);
- _label(m, bufp, &(rr[i].known.srv.name));
- break;
- default:
- *bufp += rr[i].rdlength;
+
+ for (i=0; i < count; i++) {
+ /* Extract the name, type, class, tt and record data length from the
+ buffer. The buffer pointer is automatically incremented by each call
+ tp nut2xxx
+ */
+ ExtractLabel(msg, buf, &(rr[i].name));
+ rr[i].type = DnsNet2Short(buf);
+ rr[i].class = DnsNet2Short(buf);
+ rr[i].ttl = DnsNet2Long(buf);
+ rr[i].rdlength = DnsNet2Short(buf);
+
+ /* Sanity checking the length */
+ if ((rr[i].rdlength + (*buf - msg->buf) > MAX_PACKET_LEN) ||
+ (msg->len + rr[i].rdlength > MAX_PACKET_LEN)) {
+ return -1;
+ }
+
+ /* Length was ok, make a copy of the data */
+ rr[i].rdata = msg->packet + msg->len;
+
+ msg->len += rr[i].rdlength;
+ memcpy(rr[i].rdata, *buf, rr[i].rdlength);
+
+ /* Parse known message types */
+ switch (rr[i].type) {
+ case RRTYPE_A:
+ if(msg->len + 16 > MAX_PACKET_LEN) {
+ return -1;
+ }
+ rr[i].known.a.name = msg->packet + msg->len;
+ msg->len += 16;
+ sprintf(rr[i].known.a.name, "%d.%d.%d.%d", (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]);
+ rr[i].known.a.ip = DnsNet2Long(buf);
+ break;
+
+ case RRTYPE_NS:
+ ExtractLabel(msg, buf, &(rr[i].known.ns.name));
+ break;
+
+ case RRTYPE_CNAME:
+ ExtractLabel(msg, buf, &(rr[i].known.cname.name));
+ break;
+
+ case RRTYPE_PTR:
+ ExtractLabel(msg, buf, &(rr[i].known.ptr.name));
+ break;
+
+ case RRTYPE_SRV:
+ rr[i].known.srv.priority = DnsNet2Short(buf);
+ rr[i].known.srv.weight = DnsNet2Short(buf);
+ rr[i].known.srv.port = DnsNet2Short(buf);
+ ExtractLabel(msg, buf, &(rr[i].known.srv.name));
+ break;
+
+ default:
+ *buf += rr[i].rdlength;
}
}
return 0;
}
-void message_parse(struct message *m, unsigned char *packet)
+
+/*!
+ * \brief Parse DNS packet into message format
+ *
+ * The packet must be at least MAX_PACKET_LEN bytes in size and must be allocated clean (zeroed)
+ *
+ * \param msg DNS message
+ * \param packet Package buffer
+ */
+void DnsParseMsg(DNSMESSAGE *msg, uint8_t *packet)
{
- unsigned char *buf;
+ uint8_t *buf;
int i;
-
- if(packet == 0 || m == 0) return;
-
- // keep all our mem in one (aligned) block for easy freeing
- #define my(x,y,t) while(m->_len&7) m->_len++; (x) = (t *) (m->_packet + m->_len); m->_len += (sizeof (t) * (y));
-
- // header stuff bit crap
- m->_buf = buf = packet;
- m->id = net2short(&buf);
- if(buf[0] & 0x80) m->header.qr = 1;
- m->header.opcode = (buf[0] & 0x78) >> 3;
- if(buf[0] & 0x04) m->header.aa = 1;
- if(buf[0] & 0x02) m->header.tc = 1;
- if(buf[0] & 0x01) m->header.rd = 1;
- if(buf[1] & 0x80) m->header.ra = 1;
- m->header.z = (buf[1] & 0x70) >> 4;
- m->header.rcode = buf[1] & 0x0F;
+
+ if((packet == 0) || (msg == 0)) {
+ return;
+ }
+
+ /* Bit decoding of the record header */
+ buf = packet;
+ msg->buf = buf;
+ msg->id = DnsNet2Short(&buf);
+// TODO: Ohne shiften auf die Bits prüfen, korrekte Bitwerte hinterlegen
+
+ if (buf[0] & 0x80) {
+ msg->header.qr = 1;
+ }
+
+ /* Shift opcode field 3 bits right for easy comparision */
+ msg->header.opcode = (buf[0] & 0x78) >> 3;
+
+ if (buf[0] & 0x01) {
+ msg->header.rd = 1;
+ }
+
+ if (buf[0] & 0x02) {
+ msg->header.tc = 1;
+ }
+
+ if (buf[0] & 0x04) {
+ msg->header.aa = 1;
+ }
+
+ if (buf[1] & 0x80) {
+ msg->header.ra = 1;
+ }
+
+ msg->header.z = (buf[1] & 0x70) >> 4;
+ msg->header.rcode = buf[1] & 0x0F;
buf += 2;
- m->qdcount = net2short(&buf);
- if(m->_len + (sizeof(struct question) * m->qdcount) > MAX_PACKET_LEN - 8) { m->qdcount = 0; return; }
- m->ancount = net2short(&buf);
- if(m->_len + (sizeof(struct resource) * m->ancount) > MAX_PACKET_LEN - 8) { m->ancount = 0; return; }
- m->nscount = net2short(&buf);
- if(m->_len + (sizeof(struct resource) * m->nscount) > MAX_PACKET_LEN - 8) { m->nscount = 0; return; }
- m->arcount = net2short(&buf);
- if(m->_len + (sizeof(struct resource) * m->arcount) > MAX_PACKET_LEN - 8) { m->arcount = 0; return; }
-
- // process questions
- my(m->qd, m->qdcount, struct question);
- for(i=0; i < m->qdcount; i++)
- {
- _label(m, &buf, &(m->qd[i].name));
- m->qd[i].type = net2short(&buf);
- m->qd[i].class = net2short(&buf);
- }
-
- // process rrs
- my(m->an, m->ancount, struct resource);
- my(m->ns, m->nscount, struct resource);
- my(m->ar, m->arcount, struct resource);
- if(_rrparse(m,m->an,m->ancount,&buf)) return;
- if(_rrparse(m,m->ns,m->nscount,&buf)) return;
- if(_rrparse(m,m->ar,m->arcount,&buf)) return;
+
+ msg->qdcount = DnsNet2Short(&buf);
+ if (msg->len + (sizeof(DNSQUESTION) * msg->qdcount) > MAX_PACKET_LEN - 8) {
+ msg->qdcount = 0;
+ return;
+ }
+
+ /* Get number of AN records */
+ msg->ancount = DnsNet2Short(&buf);
+ if (msg->len + (sizeof(DNSRESOURCE) * msg->ancount) > MAX_PACKET_LEN - 8) {
+ msg->ancount = 0;
+ return;
+ }
+
+ /* Get number of NS records */
+ msg->nscount = DnsNet2Short(&buf);
+ if (msg->len + (sizeof(DNSRESOURCE) * msg->nscount) > MAX_PACKET_LEN - 8) {
+ msg->nscount = 0;
+ return;
+ }
+
+ /* Get number of AR records */
+ msg->arcount = DnsNet2Short(&buf);
+ if (msg->len + (sizeof(DNSRESOURCE) * msg->arcount) > MAX_PACKET_LEN - 8) {
+ msg->arcount = 0;
+ return;
+ }
+
+ /* Process the questions */
+ while (msg->len & 0x07) msg->len++;
+ /* Process AN record */
+ msg->qd= (DNSQUESTION *) (msg->packet + msg->len);
+ msg->len += sizeof(DNSQUESTION) * msg->qdcount;
+
+ for(i = 0; i < msg->qdcount; i++) {
+ ExtractLabel(msg, &buf, &(msg->qd[i].name));
+ msg->qd[i].type = DnsNet2Short(&buf);
+ msg->qd[i].class = DnsNet2Short(&buf);
+ }
+
+
+ /* Process Ressource records and keep us always at a 8 byte boundary */
+
+ /* Align... */
+ while (msg->len & 0x07) msg->len++;
+ /* Process AN record */
+ msg->an = (DNSRESOURCE *) (msg->packet + msg->len);
+ msg->len += sizeof(DNSRESOURCE) * msg->ancount;
+
+ /* Align... */
+ while (msg->len & 0x07) msg->len++;
+ /* Process NS record */
+ msg->ns = (DNSRESOURCE *) (msg->packet + msg->len);
+ msg->len += sizeof(DNSRESOURCE) * msg->nscount;
+
+ /* Align... */
+ while (msg->len & 0x07) msg->len++;
+ /* Process AR record */
+ msg->ar = (DNSRESOURCE *) (msg->packet + msg->len);
+ msg->len += sizeof(DNSRESOURCE) * msg->arcount;
+
+ /* Parse AN record */
+ if (ParseRR(msg, msg->an, msg->ancount, &buf)) {
+ /* Size limit checking failed */
+ return;
+ }
+
+ /* Parse NS record */
+ if (ParseRR(msg, msg->ns, msg->nscount, &buf)) {
+ /* Size limit checking failed */
+ return;
+ }
+
+ /* Parse AR record */
+ if (ParseRR(msg, msg->ar, msg->arcount, &buf)) {
+ /* Size limit checking failed */
+ return;
+ }
}
-void message_qd(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class)
+
+/*!
+ * \brief Append a ressource record to the message
+ *
+ * \param msg DNS message
+ * \param name Hostname
+ * \param type Query type
+ * \param class Query class
+ * \param ttl TTL value
+ */
+static void DnsAppendRR(DNSMESSAGE *msg, uint8_t *name, uint16_t type, uint16_t class, uint32_t ttl)
{
- m->qdcount++;
- if(m->_buf == 0) m->_buf = m->_packet + 12; // initialization
- _host(m, &(m->_buf), name);
- short2net(type, &(m->_buf));
- short2net(class, &(m->_buf));
+ if (msg->buf == 0) {
+ /* Initialise the buffer pointer */
+ msg->buf = msg->packet + 12;
+ }
+ Host2Label(msg, &(msg->buf), name);
+ DnsShort2Net(type, &(msg->buf));
+ DnsShort2Net(class, &(msg->buf));
+ DnsLong2Net(ttl, &(msg->buf));
}
-void _rrappend(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
+
+/*!
+ * \brief Append a QD ressource record to the message
+ *
+ * Should be called first before calling DnsMsgAdd_an.
+ *
+ * \param msg DNS message
+ * \param name Hostname
+ * \param type Query type
+ * \param class Query class
+ */
+void DnsMsgAdd_qd(DNSMESSAGE *msg, uint8_t *name, uint16_t type, uint16_t class)
{
- if(m->_buf == 0) m->_buf = m->_packet + 12; // initialization
- _host(m, &(m->_buf), name);
- short2net(type, &(m->_buf));
- short2net(class, &(m->_buf));
- long2net(ttl, &(m->_buf));
+ msg->qdcount++;
+ if (msg->buf == 0) {
+ /* Initialise the buffer pointer */
+ msg->buf = msg->packet + 12;
+ }
+
+ Host2Label(msg, &(msg->buf), name);
+ DnsShort2Net(type, &(msg->buf));
+ DnsShort2Net(class, &(msg->buf));
}
-void message_an(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
+
+/*!
+ * \brief Append a AN ressource record to the message
+ *
+ * Should be called first before calling DnsMsgAdd_ns.
+ *
+ * \param msg DNS message
+ * \param name Hostname
+ * \param type Query type
+ * \param class Query class
+ */
+void DnsMsgAdd_an(DNSMESSAGE *msg, uint8_t *name, uint16_t type, uint16_t class, uint32_t ttl)
{
- m->ancount++;
- _rrappend(m,name,type,class,ttl);
+ msg->ancount++;
+ DnsAppendRR(msg, name, type, class, ttl);
}
-void message_ns(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
+
+/*!
+ * \brief Append a NS ressource record to the message
+ *
+ * Should be called first before calling DnsMsgAdd_ar.
+ *
+ * \param msg DNS message
+ * \param name Hostname
+ * \param type Query type
+ * \param class Query class
+ */
+void DnsMsgAdd_ns(DNSMESSAGE *msg, uint8_t *name, uint16_t type, uint16_t class, uint32_t ttl)
{
- m->nscount++;
- _rrappend(m,name,type,class,ttl);
+ msg->nscount++;
+ DnsAppendRR(msg, name, type, class, ttl);
}
-void message_ar(struct message *m, unsigned char *name, unsigned short int type, unsigned short int class, unsigned long int ttl)
+
+/*!
+ * \brief Append a AR ressource record to the message
+ *
+ * \param msg DNS message
+ * \param name Hostname
+ * \param type Query type
+ * \param class Query class
+ */
+void DnsMsgAdd_ar(DNSMESSAGE *msg, uint8_t *name, uint16_t type, uint16_t class, uint32_t ttl)
{
- m->arcount++;
- _rrappend(m,name,type,class,ttl);
+ msg->arcount++;
+ DnsAppendRR(msg, name, type, class, ttl);
}
-void message_rdata_long(struct message *m, unsigned long int l)
+
+/*!
+ * \brief Append resource data types block: uint32_t value
+ *
+ * \param msg DNS message
+ * \param val value
+ */
+void DnsMsgAdd_rdata_long(DNSMESSAGE *msg, uint32_t val)
{
- short2net(4, &(m->_buf));
- long2net(l, &(m->_buf));
+ DnsShort2Net(4, &(msg->buf));
+ DnsLong2Net(val, &(msg->buf));
}
-void message_rdata_name(struct message *m, unsigned char *name)
+
+/*!
+ * \brief Append resource data types block: Hostname
+ *
+ * \param msg DNS message
+ * \param name Hostname
+ */
+void DnsMsgAdd_rdata_name(DNSMESSAGE *msg, uint8_t *name)
{
- unsigned char *mybuf = m->_buf;
- m->_buf += 2;
- short2net(_host(m, &(m->_buf), name),&mybuf); // hackish, but cute
+ uint8_t *tmp_buf = msg->buf;
+ msg->buf += 2;
+ DnsShort2Net(Host2Label(msg, &(msg->buf), name), &tmp_buf);
}
-void message_rdata_srv(struct message *m, unsigned short int priority, unsigned short int weight, unsigned short int port, unsigned char *name)
+/*!
+ * \brief Append resource data types block: Service data
+ *
+ * \param msg DNS message
+ * \param priority Priority of the target host: lower value means more preferred.
+ * \param weight Relative weight for records with the same priority.
+ * \param port TCP / UDP port number of the service
+ * \param name The canonical hostname of the machine providing the service.
+ */
+void DnsMsgAdd_rdata_srv(DNSMESSAGE *msg, uint16_t priority, uint16_t weight, uint16_t port, uint8_t *name)
{
- unsigned char *mybuf = m->_buf;
- m->_buf += 2;
- short2net(priority, &(m->_buf));
- short2net(weight, &(m->_buf));
- short2net(port, &(m->_buf));
- short2net(_host(m, &(m->_buf), name) + 6, &mybuf);
+ uint8_t *tmp_buf = msg->buf;
+ msg->buf += 2;
+ DnsShort2Net(priority, &(msg->buf));
+ DnsShort2Net(weight, &(msg->buf));
+ DnsShort2Net(port, &(msg->buf));
+ DnsShort2Net(Host2Label(msg, &(msg->buf), name) + 6, &tmp_buf);
}
-void message_rdata_raw(struct message *m, unsigned char *rdata, unsigned short int rdlength)
+
+/*!
+ * \brief Append resource data types block: Raw data
+ *
+ * \param msg DNS message
+ * \param rdata Pointer to the raw data buffer
+ * \param rdlength Length of the raw data block
+ */
+void DnsMsgAdd_rdata_raw(DNSMESSAGE *msg, uint8_t *rdata, uint16_t rdlength)
{
- if((m->_buf - m->_packet) + rdlength > 4096) rdlength = 0;
- short2net(rdlength, &(m->_buf));
- memcpy(m->_buf,rdata,rdlength);
- m->_buf += rdlength;
+ if ((msg->buf - msg->packet) + rdlength > MAX_PACKET_LEN) {
+ rdlength = 0;
+ }
+ DnsShort2Net(rdlength, &(msg->buf));
+ memcpy(msg->buf, rdata, rdlength);
+ msg->buf += rdlength;
}
-unsigned char *message_packet(struct message *m)
+
+/*!
+ * \brief Generate the message packet to be send out.
+ *
+ * \return Packet buffer
+ */
+uint8_t *DnsMsg2Pkt(DNSMESSAGE *msg)
{
- unsigned char c, *buf = m->_buf;
- m->_buf = m->_packet;
- short2net(m->id, &(m->_buf));
- if(m->header.qr) m->_buf[0] |= 0x80;
- if((c = m->header.opcode)) m->_buf[0] |= (c << 3);
- if(m->header.aa) m->_buf[0] |= 0x04;
- if(m->header.tc) m->_buf[0] |= 0x02;
- if(m->header.rd) m->_buf[0] |= 0x01;
- if(m->header.ra) m->_buf[1] |= 0x80;
- if((c = m->header.z)) m->_buf[1] |= (c << 4);
- if(m->header.rcode) m->_buf[1] |= m->header.rcode;
- m->_buf += 2;
- short2net(m->qdcount, &(m->_buf));
- short2net(m->ancount, &(m->_buf));
- short2net(m->nscount, &(m->_buf));
- short2net(m->arcount, &(m->_buf));
- m->_buf = buf; // restore, so packet_len works
- return m->_packet;
+ uint8_t c, *buf = msg->buf;
+ msg->buf = msg->packet;
+ DnsShort2Net(msg->id, &(msg->buf));
+// TODO: Bits direkt ohne shiften
+ if (msg->header.qr) {
+ msg->buf[0] |= 0x80;
+ }
+
+ if ((c = msg->header.opcode)) {
+ msg->buf[0] |= (c << 3);
+ }
+ if (msg->header.aa) {
+ msg->buf[0] |= 0x04;
+ }
+
+ if (msg->header.tc) {
+ msg->buf[0] |= 0x02;
+ }
+
+ if (msg->header.rd) {
+ msg->buf[0] |= 0x01;
+ }
+
+ if (msg->header.ra) {
+ msg->buf[1] |= 0x80;
+ }
+
+ if ((c = msg->header.z)) {
+ msg->buf[1] |= (c << 4);
+ }
+
+ if (msg->header.rcode) {
+ msg->buf[1] |= msg->header.rcode;
+ }
+
+ msg->buf += 2;
+
+ DnsShort2Net(msg->qdcount, &(msg->buf));
+ DnsShort2Net(msg->ancount, &(msg->buf));
+ DnsShort2Net(msg->nscount, &(msg->buf));
+ DnsShort2Net(msg->arcount, &(msg->buf));
+
+ /* Restore the packet pointer. It is necessary for DnsMsgLen() */
+ msg->buf = buf;
+
+ /* Return the modified packet */
+ return msg->packet;
}
-int message_packet_len(struct message *m)
+
+/*!
+ * \brief Calculate message packet length
+ *
+ * \return Message packet length
+ */
+
+int DnsMsgLen(DNSMESSAGE *msg)
{
- if(m->_buf == 0) return 12;
- return m->_buf - m->_packet;
+ if(msg->buf == 0) return 12;
+ return msg->buf - msg->packet;
}
+
+/*@}*/