diff options
Diffstat (limited to 'tinyNET/src/dns/tnet_dns_rr.c')
-rw-r--r-- | tinyNET/src/dns/tnet_dns_rr.c | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/tinyNET/src/dns/tnet_dns_rr.c b/tinyNET/src/dns/tnet_dns_rr.c new file mode 100644 index 0000000..ddf3682 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_rr.c @@ -0,0 +1,452 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango.org> +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +/**@file tnet_dns_rr.c + * @brief DNS Resource Record (RFC 1034 and 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango.org> + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tnet_dns_rr.h" + +#include "tnet_dns_a.h" +#include "tnet_dns_aaaa.h" +#include "tnet_dns_cname.h" +#include "tnet_dns_mx.h" +#include "tnet_dns_naptr.h" +#include "tnet_dns_ns.h" +#include "tnet_dns_opt.h" +#include "tnet_dns_ptr.h" +#include "tnet_dns_soa.h" +#include "tnet_dns_srv.h" +#include "tnet_dns_txt.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_memory.h" +#include "tsk_debug.h" +#include "tsk_string.h" + +#include <string.h> /* strtok, strlen ... */ + + +/** Creates a new DNS RR. +*/ + +tnet_dns_rr_t* tnet_dns_rr_create() +{ + return tsk_object_new(tnet_dns_rr_def_t); +} + +/** Initializes any DNS RR (either NAPTR or SRV ...). +* @param rr The DNS RR to initialize. +* @param qtype The type of the RR. +* @param qclass The class of the RR. +* @retval Zero if succeed and non-zero error code otherwise. +*/ +int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass) +{ + if(rr){ + if(!rr->initialized){ + rr->qtype = qtype; + rr->qclass = qclass; + + rr->initialized = tsk_true; + return 0; + } + return -2; + } + return -1; +} + +/** Deinitializes any DNS RR (either NAPTR or SRV ...). +* @param rr The DNS RR to deinitialize. +* @retval Zero if succeed and non-zero error code otherwise. +*/ +int tnet_dns_rr_deinit(tnet_dns_rr_t *rr) +{ + if(rr){ + if(rr->initialized){ + TSK_FREE(rr->name); + TSK_FREE(rr->rpdata); + + rr->initialized = tsk_false; + return 0; + } + return -2; + } + return -1; +} + +/** Deserialize <character-string>. +*/ +int tnet_dns_rr_charstring_deserialize(const void* data, char** charstring, tsk_size_t *offset) +{ + /* RFC 1035 - 3.3. Standard RRs + <character-string> is a single length octet followed by that number of characters. + <character-string> is treated as binary information, and can be up to 256 characters in + length (including the length octet). + */ + uint8_t* dataPtr = (((uint8_t*)data)+ *offset); + uint8_t length = *dataPtr; + + *charstring = tsk_strndup((const char*)(dataPtr + 1), length); + *offset += (1 + length); + + return 0; +} + +/** Deserializes a QName. +*/ +int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset) +{ + /* RFC 1035 - 4.1.4. Message compression + + The pointer takes the form of a two octet sequence: + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1 1| OFFSET | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + uint8_t* dataPtr = (((uint8_t*)data) + *offset); + unsigned usingPtr = 0; /* Do not change. */ + + while(*dataPtr){ + usingPtr = ((*dataPtr & 0xC0) == 0xC0); + + if(usingPtr){ + tsk_size_t ptr_offset = (*dataPtr & 0x3F); + ptr_offset = ptr_offset << 8 | *(dataPtr+1); + + *offset += 2; + return tnet_dns_rr_qname_deserialize(data, name, &ptr_offset); + } + else{ + uint8_t length; + + if(*name){ + tsk_strcat(name, "."); + } + + length = *dataPtr; + *offset+=1, dataPtr++; + + tsk_strncat(name, (const char*)dataPtr, length); + *offset += length, dataPtr += length; + } + } + + *offset+=1; + + return 0; +} + +//int tnet_dns_rr_qname_deserialize(const void* data, tsk_size_t size, char** name, tsk_size_t *offset) +//{ +// /* RFC 1035 - 4.1.4. Message compression +// +// The pointer takes the form of a two octet sequence: +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 1 1| OFFSET | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// */ +// uint8_t* dataPtr = (((uint8_t*)data) + *offset); +// uint8_t* dataEnd = (dataPtr + size); +// unsigned usingPtr = 0; /* Do not change. */ +// unsigned islast = 0; +// +// while(!islast) +// { +// usingPtr = ((*dataPtr & 0xC0) == 0xC0); +// +// if(usingPtr) +// { +// uint8_t *Ptr; +// uint16_t ptr_offset = (*dataPtr & 0x3F); +// ptr_offset = ptr_offset << 8 | *(dataPtr+1); +// Ptr = ((uint8_t*)data) + ptr_offset; +// +// tnet_qname_label_parse(Ptr, (dataEnd - Ptr), name, &islast); +// *offset += 2, dataPtr += 2; +// } +// else +// { +// tsk_size_t length = tnet_qname_label_parse(dataPtr, size, name, &islast); +// *offset += length, dataPtr += length; +// } +// } +// +// *offset += usingPtr ? 0 : 1; +// +// return 0; +//} + +/** Serializes a QName. +*/ +int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output) +{ + /* + QNAME a domain name represented as a sequence of labels, where + each label consists of a length octet followed by that + number of octets. The domain name terminates with the + zero length octet for the null label of the root. Note + that this field may be an odd number of octets; no + padding is used. + + Example: "doubango.com" ==> 8doubango3comNULL + */ + static uint8_t null = 0; + + if(qname){ + char* _qname = tsk_strdup(qname); + char* label = strtok(_qname, "."); + + while(label){ + uint8_t length = tsk_strlen(label); + tsk_buffer_append(output, &length, 1); + tsk_buffer_append(output, label, tsk_strlen(label)); + + label = strtok (tsk_null, "."); + } + + TSK_FREE(_qname); + } + + /* terminates domain name */ + tsk_buffer_append(output, &null, 1); + + return 0; +} + +/** Deserializes a DNS RR. +*/ +tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset) +{ + tnet_dns_rr_t *rr = tsk_null; + uint8_t* dataStart = (uint8_t*)data; + uint8_t* dataPtr = (dataStart + *offset); + //uint8_t* dataEnd = (dataPtr+size); + tnet_dns_qtype_t qtype; + tnet_dns_qclass_t qclass; + uint32_t ttl; + uint16_t rdlength; + char* qname = tsk_null; + + /* Check validity */ + if(!dataPtr || !size){ + goto bail; + } + + /* == Parse QNAME == */ + tnet_dns_rr_qname_deserialize(dataStart, &qname, offset); + dataPtr = (dataStart + *offset); + /* == Parse QTYPE == */ + qtype = (tnet_dns_qtype_t)tnet_ntohs_2(dataPtr); + dataPtr += 2, *offset += 2; + /* == Parse QCLASS == */ + qclass = (tnet_dns_qclass_t)tnet_ntohs_2(dataPtr); + dataPtr += 2, *offset += 2; + /* == Parse TTL == */ + ttl = tnet_htonl_2(dataPtr); + dataPtr += 4, *offset += 4; + /* == Parse RDLENGTH == */ + rdlength = tnet_ntohs_2(dataPtr); + dataPtr += 2, *offset += 2; + + switch(qtype){ + case qtype_a: + { + rr = (tnet_dns_rr_t *)tnet_dns_a_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_aaaa: + { + rr = (tnet_dns_rr_t *)tnet_dns_aaaa_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_cname: + { + rr = (tnet_dns_rr_t *)tnet_dns_cname_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_mx: + { + rr = (tnet_dns_rr_t *)tnet_dns_mx_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_naptr: + { + rr = (tnet_dns_rr_t *)tnet_dns_naptr_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_ns: + { + rr = (tnet_dns_rr_t *)tnet_dns_ns_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_opt: + { + unsigned payload_size = qclass; + rr = (tnet_dns_rr_t *)tnet_dns_opt_create(payload_size); + break; + } + + case qtype_ptr: + { + rr = (tnet_dns_rr_t *)tnet_dns_ptr_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_soa: + { + rr = (tnet_dns_rr_t *)tnet_dns_soa_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_srv: + { + rr = (tnet_dns_rr_t *)tnet_dns_srv_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_txt: + { + rr = (tnet_dns_rr_t *)tnet_dns_txt_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + default: + { + TSK_DEBUG_ERROR("NOT IMPLEMENTED"); + break; + } + } + +bail: + TSK_FREE(qname); + + *offset += rdlength; + return rr; +} + +/** Serializes a DNS RR. +*/ +int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output) +{ + if(!rr || !output){ + return -1; + } + + /*=== NAME ===*/ + { + tnet_dns_rr_qname_serialize(rr->name, output); + } + + /*=== TYPE ===*/ + { + uint16_t qtype = tnet_htons(rr->qtype); + tsk_buffer_append(output, &(qtype), 2); + } + + /*=== CLASS ===*/ + { + uint16_t qclass = tnet_htons(rr->qclass); + tsk_buffer_append(output, &(qclass), 2); + } + + /*=== TTL ===*/ + { + uint32_t ttl = tnet_htonl(rr->ttl); + tsk_buffer_append(output, &(ttl), 4); + } + + /*=== RDLENGTH ===*/ + { + uint16_t length = tnet_htons(rr->rdlength); + tsk_buffer_append(output, &(length), 2); + } + + /*=== RDATA : Request never contains data + ===*/ + if(!rr->rpdata){ + goto done; + } + + switch(rr->qtype){ + case qtype_a: + case qtype_aaaa: + case qtype_cname: + case qtype_mx: + case qtype_naptr: + case qtype_ns: + case qtype_opt: + case qtype_ptr: + case qtype_soa: + case qtype_srv: + case qtype_txt: + default: + { + TSK_DEBUG_WARN("DNS Request should not contains RDATA (not supported)."); + break; + } + } + +done: + return 0; +} + + +//================================================================================================= +// [[DNS RR]] object definition +// +static tsk_object_t* tnet_dns_rr_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_rr_t *rr = self; + if(rr){ + tnet_dns_rr_init(rr, qtype_any, qclass_any); + } + return self; +} + +static tsk_object_t* tnet_dns_rr_dtor(tsk_object_t * self) +{ + tnet_dns_rr_t *rr = self; + if(rr){ + tnet_dns_rr_deinit(rr); + } + return self; +} + +static const tsk_object_def_t tnet_dns_rr_def_s = +{ + sizeof(tnet_dns_rr_t), + tnet_dns_rr_ctor, + tnet_dns_rr_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_rr_def_t = &tnet_dns_rr_def_s; |