/*************************************************************************** * DNSData.h -- The DNSData Class represents the data in a DNS exchange. * * It can be used to craft and parse DNS payloads. * * * ***********************IMPORTANT NMAP LICENSE TERMS************************ * * * The Nmap Security Scanner is (C) 1996-2013 Insecure.Com LLC. Nmap is * * also a registered trademark of Insecure.Com LLC. This program is free * * software; you may redistribute and/or modify it under the terms of the * * GNU General Public License as published by the Free Software * * Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE CLARIFICATIONS * * AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your right to use, * * modify, and redistribute this software under certain conditions. If * * you wish to embed Nmap technology into proprietary software, we sell * * alternative licenses (contact sales@nmap.com). Dozens of software * * vendors already license Nmap technology such as host discovery, port * * scanning, OS detection, version detection, and the Nmap Scripting * * Engine. * * * * Note that the GPL places important restrictions on "derivative works", * * yet it does not provide a detailed definition of that term. To avoid * * misunderstandings, we interpret that term as broadly as copyright law * * allows. For example, we consider an application to constitute a * * derivative work for the purpose of this license if it does any of the * * following with any software or content covered by this license * * ("Covered Software"): * * * * o Integrates source code from Covered Software. * * * * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db * * or nmap-service-probes. * * * * o Is designed specifically to execute Covered Software and parse the * * results (as opposed to typical shell or execution-menu apps, which will * * execute anything you tell them to). * * * * o Includes Covered Software in a proprietary executable installer. The * * installers produced by InstallShield are an example of this. Including * * Nmap with other software in compressed or archival form does not * * trigger this provision, provided appropriate open source decompression * * or de-archiving software is widely available for no charge. For the * * purposes of this license, an installer is considered to include Covered * * Software even if it actually retrieves a copy of Covered Software from * * another source during runtime (such as by downloading it from the * * Internet). * * * * o Links (statically or dynamically) to a library which does any of the * * above. * * * * o Executes a helper program, module, or script to do any of the above. * * * * This list is not exclusive, but is meant to clarify our interpretation * * of derived works with some common examples. Other people may interpret * * the plain GPL differently, so we consider this a special exception to * * the GPL that we apply to Covered Software. Works which meet any of * * these conditions must conform to all of the terms of this license, * * particularly including the GPL Section 3 requirements of providing * * source code and allowing free redistribution of the work as a whole. * * * * As another special exception to the GPL terms, Insecure.Com LLC grants * * permission to link the code of this program with any version of the * * OpenSSL library which is distributed under a license identical to that * * listed in the included docs/licenses/OpenSSL.txt file, and distribute * * linked combinations including the two. * * * * Any redistribution of Covered Software, including any derived works, * * must obey and carry forward all of the terms of this license, including * * obeying all GPL rules and restrictions. For example, source code of * * the whole work must be provided and free redistribution must be * * allowed. All GPL references to "this License", are to be treated as * * including the terms and conditions of this license text as well. * * * * Because this license imposes special exceptions to the GPL, Covered * * Work may not be combined (even as part of a larger work) with plain GPL * * software. The terms, conditions, and exceptions of this license must * * be included as well. This license is incompatible with some other open * * source licenses as well. In some cases we can relicense portions of * * Nmap or grant special permissions to use it in other open source * * software. Please contact fyodor@nmap.org with any such requests. * * Similarly, we don't incorporate incompatible open source software into * * Covered Software without special permission from the copyright holders. * * * * If you have any questions about the licensing restrictions on using * * Nmap in other works, are happy to help. As mentioned above, we also * * offer alternative license to integrate Nmap into proprietary * * applications and appliances. These contracts have been sold to dozens * * of software vendors, and generally include a perpetual license as well * * as providing for priority support and updates. They also fund the * * continued development of Nmap. Please email sales@nmap.com for further * * information. * * * * If you have received a written license agreement or contract for * * Covered Software stating terms other than these, you may choose to use * * and redistribute Covered Software under those terms instead of these. * * * * Source is provided to this software because we believe users have a * * right to know exactly what a program is going to do before they run it. * * This also allows you to audit the software for security holes (none * * have been found so far). * * * * Source code also allows you to port Nmap to new platforms, fix bugs, * * and add new features. You are highly encouraged to send your changes * * to the dev@nmap.org mailing list for possible incorporation into the * * main distribution. By sending these changes to Fyodor or one of the * * Insecure.Org development mailing lists, or checking them into the Nmap * * source code repository, it is understood (unless you specify otherwise) * * that you are offering the Nmap Project (Insecure.Com LLC) the * * unlimited, non-exclusive right to reuse, modify, and relicense the * * code. Nmap will always be available Open Source, but this is important * * because the inability to relicense code has caused devastating problems * * for other Free Software projects (such as KDE and NASM). We also * * occasionally relicense the code to third parties as discussed above. * * If you wish to specify special license conditions of your * * contributions, just say so when you send them. * * * * This program 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 Nmap * * license file for more details (it's in a COPYING file included with * * Nmap, and also available from https://svn.nmap.org/nmap/COPYING * * * ***************************************************************************/ #include "DNSData.h" /******************************************************************************/ /* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */ /******************************************************************************/ DNSData::DNSData(){ this->reset(); } /* End of DNSData contructor */ DNSData::~DNSData(){ if(this->data!=NULL){ free(this->data); this->data=NULL; } } /* End of DNSData destructor */ /** Sets every attribute to its default value */ void DNSData::reset(){ this->data=NULL; this->length=0; } /* End of reset() */ /******************************************************************************/ /* PacketElement:: OVERWRITTEN METHODS */ /******************************************************************************/ u8 * DNSData::getBufferPointer(){ return this->getBufferPointer(NULL); } /* End of getBufferPointer() */ u8 * DNSData::getBufferPointer(int *mylen){ if(mylen!=NULL) *mylen=this->length; return reinterpret_cast(this->data); } /* End of getBufferPointer() */ /** Added for consistency with the rest of classes of the PacketElement family. */ int DNSData::storeRecvData(const u8 *buf, size_t len){ return this->setDNSResponse(buf, len); } /* End of storeRecvData() */ /* Returns a protocol identifier. This is used by packet parsing funtions * that return linked lists of PacketElement objects, to determine the protocol * the object represents. */ int DNSData::protocol_id() const { return DATA_TYPE_DNS; } /* End of protocol_id() */ /** Determines if the data stored in the object after an storeRecvData() call * is valid and safe to use. This mainly checks the length of the data but may * also test the value of certain protocol fields to ensure their correctness. * @return the length, in bytes, of the payload, if its found to be valid or * OP_FAILURE (-1) otherwise. */ int DNSData::validate(){ /* TODO: Other checks */ return this->length; } /* End of validate() */ /** Prints the contents of the header and calls print() on the next protocol * header in the chain (if there is any). * @return OP_SUCCESS on success and OP_FAILURE in case of error. */ int DNSData::print(FILE *output, int detail) const { /* TODO */ fprintf(output, "Payload["); fprintf(output, "%d byte%s]", this->length, (this->length!=1)? "s":""); if(this->next!=NULL){ print_separator(output, detail); next->print(output, detail); } return OP_SUCCESS; } /* End of print() */ /******************************************************************************/ /* PROTOCOL-SPECIFIC METHODS */ /******************************************************************************/ /* stores the response of a DNS server in the buffer. The response can* * then be acquired with getAddress and getHostname */ int DNSData::setDNSResponse(const u8 *buf, size_t len){ if(buf == NULL || allocateData(len) == OP_FAILURE || len < sizeof(dns_msg_t)) { return OP_FAILURE; } memcpy(this->data, buf, len); return OP_SUCCESS; } /* End of setDNSResponse() */ int DNSData::setDNSResponse(const char *str){ if(str==NULL) return OP_FAILURE; else return this->setDNSResponse((const u8*)str, strlen(str)); } /* End of setDNSResponse() */ /* returns the type of the dns request currently stored in the buffer */ int DNSData::getType() const{ return data->flags_h & 0x80; } /* creates the request, using the arguments. Results can then be * * acquired with getBufferPointer */ int DNSData::setHostnameToResolve(char *address, u16 id){ initialiseStruct(strlen(address)); data->id = htons(id); insertAddress(address); return OP_SUCCESS; } int DNSData::setAddressToResolve(u32 d, u16 id){ struct in_addr addr = {d}; return setAddressToResolve(addr, id); } int DNSData::setAddressToResolve(struct in_addr d, u16 id){ char *hostname = NULL; ipToRHostname(d, &hostname); initialiseStruct(strlen(hostname)); data->id = htons(id); insertAddress(hostname); free(hostname); /* find the end of the address * We don't need to check the return value, * because we just created the struct at the right length * and the address at 0 should be valid */ int contentIndex = findEndDnsName(0); query_footer_t* footer; footer = (query_footer_t*)(data->content + contentIndex); footer->q_type = htons(0xc); footer->q_class = htons(0x1); return OP_SUCCESS; } /* extracts the result of the response currently in the buffer. Will * * send an error if the type is not valid */ int DNSData::getAddress(u32 *d) const { struct in_addr tmp = {0}; int response; response = getAddress(&tmp); *d = tmp.s_addr; return response; } int DNSData::getAddress(struct in_addr *d) const { return OP_SUCCESS; } int DNSData::getHostname(char **address) const { /* TODO: error codes management */ return OP_SUCCESS; } /* gets the id in the currently stored data buffer */ int DNSData::getId(u16 *id) const { /* check if data is set */ if(data == NULL) { return OP_FAILURE; } *id =ntohs(data->id); return OP_SUCCESS; } /******************************************************************************/ /* PRIVATE HELPER FUNCTION */ /******************************************************************************/ /* finds the end of a name in DNS format */ int DNSData::findEndDnsName(int start) { while(this->length > (int) DNS_HDR_LEN + start && data->content[start] != '\x0') { /* is compression used? */ if( (data->content[start] & 0xC0) == 0xC0) { start++; break; } start += data->content[start]+ 1; } start++; return this->length > (int)DNS_HDR_LEN + start ? start : -1; } /* tries to reuse the structure if it is long enough, creates a new one * if not */ int DNSData::allocateData(size_t len) { /* If buffer had already been set, try to reuse it. */ if(this->data!=NULL){ /* if the buffer is not big enough, free it, if not simply do nothing */ if( this->length < (int)len ){ free(this->data); } } /* if the buffer wasn't used before or has been freed because it was too * short, allocate one */ if(this->data == NULL) { if((this->data= reinterpret_cast(calloc(len, sizeof(u8))))==NULL) return OP_FAILURE; } this->length=(int)len; return OP_SUCCESS; } /* takes an address and puts it at the start of content in the DNS format */ int DNSData::insertAddress(char *address) { /* We need to replace the dots between labels with the size of the next * * label, and also put a size at the start */ size_t currentIndex = 0; /* index going threw each label to find the end */ size_t startOfLabel = 0; /* index keeping the start of the current label */ while( address[startOfLabel + currentIndex] != 0 && startOfLabel + currentIndex + DNS_HDR_LEN < (size_t)this->length ) { /* Is this the end of the current label? */ if( address[startOfLabel + currentIndex] == '.' ) { /* check if the lable is not longer than 63 chars (DNS rule) */ if(currentIndex > 63) { return OP_FAILURE; } /* insert the length of the next label */ data->content[startOfLabel] = currentIndex; /* copy the label */ strncpy((char*)data->content + startOfLabel + 1, address+ startOfLabel, currentIndex); /* change the indexes value, to start the new label */ startOfLabel += currentIndex + 1; currentIndex = 0; } else { currentIndex++; } } if(startOfLabel + currentIndex + DNS_HDR_LEN < (size_t) this->length) { /* the last hostname still needs to be added */ data->content[startOfLabel] = currentIndex; strncpy((char*)data->content + startOfLabel + 1, address + startOfLabel, currentIndex); return OP_SUCCESS; } else { return OP_FAILURE; } } int DNSData::ipToRHostname(struct in_addr d, char ** hostname){ /* maximum size, if every number in the ip takes 3 chars * 4 numbers * 4 chars (3 for the number + 1 dot) + "in-addr.arpa" + '\0' */ *hostname = (char *)safe_malloc(29 * sizeof(char)); unsigned char *ip = (unsigned char *) &d.s_addr; size_t offset = 0; /* How far have we already advanced in the buffer? */ int ip_part = 3; /* index on our advancedement on the ip part */ /* for each label in the ip */ while(ip_part >= 0) { /* add the label to our hostname in ascii */ snprintf((*hostname) + offset, 4, "%d", ip[ip_part]); offset = strlen(*hostname); /* add a point at the end */ (*hostname)[offset] = '.'; offset++; (*hostname)[offset] = '\0'; /* move to the next part */ ip_part--; } /* add the remaining part */ memcpy((*hostname) + offset, "in-addr.arpa", 13); return OP_SUCCESS; } /* initialises the struct with default values */ int DNSData::initialiseStruct(size_t sizeOfAddress) { /* calculate the size of the struct to make, by calculating the size * of the hostname */ size_t len = sizeOfAddress; /* We need to add 2 for the extra char at the beginning and the \0 at the * * end of the string, as well as the header of the structure, and the last * * two fields */ len += 2 + DNS_HDR_LEN + 2 * sizeof(u16); if(allocateData(len) == OP_FAILURE){ return OP_FAILURE; } /* fill the header */ data->id = htons(0x0); data->flags_h = 0x01; data->flags_l = 0x00; data->zocount = htons(0x1); /* we are asking 1 question */ data->prcount = htons(0x0); data->upcount = htons(0x0); data->adcount = htons(0x0); return OP_SUCCESS; }