Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

dns_resource_record.cpp

Go to the documentation of this file.
00001 /*
00002 **  ClanLib SDK
00003 **  Copyright (c) 1997-2005 The ClanLib Team
00004 **
00005 **  This software is provided 'as-is', without any express or implied
00006 **  warranty.  In no event will the authors be held liable for any damages
00007 **  arising from the use of this software.
00008 **
00009 **  Permission is granted to anyone to use this software for any purpose,
00010 **  including commercial applications, and to alter it and redistribute it
00011 **  freely, subject to the following restrictions:
00012 **
00013 **  1. The origin of this software must not be misrepresented; you must not
00014 **     claim that you wrote the original software. If you use this software
00015 **     in a product, an acknowledgment in the product documentation would be
00016 **     appreciated but is not required.
00017 **  2. Altered source versions must be plainly marked as such, and must not be
00018 **     misrepresented as being the original software.
00019 **  3. This notice may not be removed or altered from any source distribution.
00020 **
00021 **  Note: Some of the libraries ClanLib link to may have additional
00022 **  requirements or restrictions.
00023 **
00024 **  File Author(s):
00025 **
00026 **    Magnus Norddahl
00027 */
00028 
00029 #include "precomp.h"
00030 #include "dns_resource_record.h"
00031 #include "string_help.h"
00032 #include "exception.h"
00033 #ifdef WIN32
00034 #include <winsock.h>
00035 #else
00036 #include <sys/types.h>
00037 #include <netinet/in.h>
00038 #endif
00039 
00041 // CL_DNSResourceRecord Construction:
00042 
00043 CL_DNSResourceRecord::CL_DNSResourceRecord()
00044 : record_offset(0), rdata_offset(0), rdata_length(0)
00045 {
00046 }
00047         
00048 CL_DNSResourceRecord::CL_DNSResourceRecord(const CL_DNSResourceRecord &other)
00049 : record_offset(0), rdata_offset(0), rdata_length(0)
00050 {
00051         packet = other.packet;
00052         record_offset = other.record_offset;
00053         rdata_offset = other.rdata_offset;
00054         rdata_length = other.rdata_length;
00055 }
00056 
00057 CL_DNSResourceRecord::~CL_DNSResourceRecord()
00058 {
00059 }
00060 
00062 // CL_DNSResourceRecord Attributes:
00063 
00064 CL_String CL_DNSResourceRecord::get_name() const
00065 {
00066         return read_domain_name(packet, record_offset);
00067 }
00068 
00069 CL_String CL_DNSResourceRecord::get_type() const
00070 {
00071         int type_offset = find_domain_name_end(packet, record_offset);
00072         int rr_data_offset = type_offset + 2 + 2 + 4 + 2;
00073         if (packet.get_size() < rr_data_offset)
00074                 throw CL_Exception(TEXT("Premature end of DNS resource record"));
00075         unsigned short rr_type = ntohs(*(unsigned short *) (packet.get_data() + type_offset));
00076         unsigned short rr_class = ntohs(*(unsigned short *) (packet.get_data() + type_offset+2));
00077         unsigned int rr_ttl = ntohl(*(unsigned int *) (packet.get_data() + type_offset+4));
00078         unsigned short rr_data_length = ntohs(*(unsigned short *) (packet.get_data() + type_offset+8));
00079         return type_from_int(rr_type);
00080 }
00081 
00082 CL_String CL_DNSResourceRecord::get_class() const
00083 {
00084         int type_offset = find_domain_name_end(packet, record_offset);
00085         int rr_data_offset = type_offset + 2 + 2 + 4 + 2;
00086         if (packet.get_size() < rr_data_offset)
00087                 throw CL_Exception(TEXT("Premature end of DNS resource record"));
00088         unsigned short rr_type = ntohs(*(unsigned short *) (packet.get_data() + type_offset));
00089         unsigned short rr_class = ntohs(*(unsigned short *) (packet.get_data() + type_offset+2));
00090         unsigned int rr_ttl = ntohl(*(unsigned int *) (packet.get_data() + type_offset+4));
00091         unsigned short rr_data_length = ntohs(*(unsigned short *) (packet.get_data() + type_offset+8));
00092         return class_from_int(rr_class);
00093 }
00094 
00095 int CL_DNSResourceRecord::get_ttl() const
00096 {
00097         int type_offset = find_domain_name_end(packet, record_offset);
00098         int rr_data_offset = type_offset + 2 + 2 + 4 + 2;
00099         if (packet.get_size() < rr_data_offset)
00100                 throw CL_Exception(TEXT("Premature end of DNS resource record"));
00101         unsigned short rr_type = ntohs(*(unsigned short *) (packet.get_data() + type_offset));
00102         unsigned short rr_class = ntohs(*(unsigned short *) (packet.get_data() + type_offset+2));
00103         unsigned int rr_ttl = ntohl(*(unsigned int *) (packet.get_data() + type_offset+4));
00104         unsigned short rr_data_length = ntohs(*(unsigned short *) (packet.get_data() + type_offset+8));
00105         return rr_ttl;
00106 }
00107 
00108 const CL_ByteArray &CL_DNSResourceRecord::get_packet() const
00109 {
00110         return packet;
00111 }
00112 
00113 int CL_DNSResourceRecord::get_record_offset() const
00114 {
00115         return record_offset;
00116 }
00117 
00118 int CL_DNSResourceRecord::get_rdata_offset() const
00119 {
00120         return rdata_offset;
00121 }
00122 
00123 int CL_DNSResourceRecord::get_rdata_length() const
00124 {
00125         return rdata_length;
00126 }
00127 
00128 CL_String CL_DNSResourceRecord::get_cname_cname() const
00129 {
00130         return read_domain_name(packet, rdata_offset);
00131 }
00132 
00133 int CL_DNSResourceRecord::get_mx_preference() const
00134 {
00135         if (packet.get_size() < rdata_offset + 2)
00136                 throw CL_Exception(TEXT("Premature end of resource data section"));
00137         short *preference = (short *) (packet.get_data() + rdata_offset);
00138         return ntohs(*preference);
00139 }
00140         
00141 CL_String CL_DNSResourceRecord::get_mx_exchange() const
00142 {
00143         return read_domain_name(packet, rdata_offset + 2);
00144 }
00145         
00146 CL_String CL_DNSResourceRecord::get_ns_nsdname() const
00147 {
00148         return read_domain_name(packet, rdata_offset);
00149 }
00150         
00151 CL_String CL_DNSResourceRecord::get_ptr_ptrdname() const
00152 {
00153         return read_domain_name(packet, rdata_offset);
00154 }
00155         
00156 CL_String CL_DNSResourceRecord::get_soa_mname() const
00157 {
00158         return read_domain_name(packet, rdata_offset);
00159 }
00160         
00161 CL_String CL_DNSResourceRecord::get_soa_rname() const
00162 {
00163         int pos = find_domain_name_end(packet, rdata_offset);
00164         return read_domain_name(packet, pos);
00165 }
00166         
00167 unsigned int CL_DNSResourceRecord::get_soa_serial() const
00168 {
00169         int pos = find_domain_name_end(packet, rdata_offset);
00170         pos = find_domain_name_end(packet, pos);
00171         if (packet.get_size() < pos + 4)
00172                 throw CL_Exception(TEXT("Premature end of resource data section"));
00173         unsigned int *serial = (unsigned int *) (packet.get_data() + pos);
00174         return ntohl(*serial);
00175 }
00176         
00177 int CL_DNSResourceRecord::get_soa_refresh() const
00178 {
00179         int pos = find_domain_name_end(packet, rdata_offset);
00180         pos = find_domain_name_end(packet, pos) + 4;
00181         if (packet.get_size() < pos + 4)
00182                 throw CL_Exception(TEXT("Premature end of resource data section"));
00183         int *refresh = (int *) (packet.get_data() + pos);
00184         return ntohl(*refresh);
00185 }
00186         
00187 int CL_DNSResourceRecord::get_soa_retry() const
00188 {
00189         int pos = find_domain_name_end(packet, rdata_offset);
00190         pos = find_domain_name_end(packet, pos) + 8;
00191         if (packet.get_size() < pos + 4)
00192                 throw CL_Exception(TEXT("Premature end of resource data section"));
00193         int *retry = (int *) (packet.get_data() + pos);
00194         return ntohl(*retry);
00195 }
00196         
00197 int CL_DNSResourceRecord::get_soa_expire() const
00198 {
00199         int pos = find_domain_name_end(packet, rdata_offset);
00200         pos = find_domain_name_end(packet, pos) + 12;
00201         if (packet.get_size() < pos + 4)
00202                 throw CL_Exception(TEXT("Premature end of resource data section"));
00203         int *expire = (int *) (packet.get_data() + pos);
00204         return ntohl(*expire);
00205 }
00206         
00207 unsigned int CL_DNSResourceRecord::get_soa_minimum() const
00208 {
00209         int pos = find_domain_name_end(packet, rdata_offset);
00210         pos = find_domain_name_end(packet, pos) + 16;
00211         if (packet.get_size() < pos + 4)
00212                 throw CL_Exception(TEXT("Premature end of resource data section"));
00213         unsigned int *minimum = (unsigned int *) (packet.get_data() + pos);
00214         return ntohl(*minimum);
00215 }
00216         
00217 unsigned int CL_DNSResourceRecord::get_wks_address() const
00218 {
00219         if (packet.get_size() < rdata_offset + 4)
00220                 throw CL_Exception(TEXT("Premature end of resource data section"));
00221         unsigned int *address = (unsigned int *) (packet.get_data() + rdata_offset);
00222         return ntohs(*address);
00223 }
00224         
00225 unsigned char CL_DNSResourceRecord::get_wks_protocol() const
00226 {
00227         if (packet.get_size() < rdata_offset + 5)
00228                 throw CL_Exception(TEXT("Premature end of resource data section"));
00229         unsigned char *protocol = (unsigned char *) (packet.get_data() + rdata_offset + 4);
00230         return *protocol;
00231 }
00232         
00233 CL_ByteArray CL_DNSResourceRecord::get_wks_bit_map() const
00234 {
00235         int len = rdata_length - 5;
00236         if (len < 0)
00237                 throw CL_Exception(TEXT("Premature end of resource data section"));
00238         CL_ByteArray bit_map(len);
00239         memcpy(bit_map.get_data(), packet.get_data() + rdata_offset + 5, len);
00240         return bit_map;
00241 }
00242 
00244 // CL_DNSResourceRecord Operation:
00245 
00246 CL_DNSResourceRecord &CL_DNSResourceRecord::operator =(const CL_DNSResourceRecord &other)
00247 {
00248         packet = other.packet;
00249         record_offset = other.record_offset;
00250         rdata_offset = other.rdata_offset;
00251         rdata_length = other.rdata_length;
00252         return *this;
00253 }
00254 
00255 void CL_DNSResourceRecord::set_record(const CL_ByteArray &new_packet, int new_record_offset)
00256 {
00257         // Verify size sanity of generic record fields:
00258         
00259         int type_offset = find_domain_name_end(new_packet, new_record_offset);
00260         int rr_data_offset = type_offset + 2 + 2 + 4 + 2;
00261         if (new_packet.get_size() < rr_data_offset)
00262                 throw CL_Exception(TEXT("Premature end of DNS resource record"));
00263         
00264         unsigned short rr_type = ntohs(*(unsigned short *) (new_packet.get_data() + type_offset));
00265         unsigned short rr_class = ntohs(*(unsigned short *) (new_packet.get_data() + type_offset+2));
00266         unsigned int rr_ttl = ntohl(*(unsigned int *) (new_packet.get_data() + type_offset+4));
00267         unsigned short rr_data_length = ntohs(*(unsigned short *) (new_packet.get_data() + type_offset+8));
00268 
00269         if (new_packet.get_size() < rr_data_offset + rr_data_length)
00270                 throw CL_Exception(TEXT("Premature end of DNS resource record RDATA section"));
00271 
00272         // Generic record fields seem sane. Store record:
00273 
00274         packet = new_packet;
00275         rdata_offset = rr_data_offset;
00276         rdata_length = rr_data_length;
00277         record_offset = new_record_offset;
00278 }
00279 
00280 struct RRType
00281 {
00282         char *name;
00283         int value;
00284         char *description;
00285 };
00286 
00287 static RRType rr_types[] =
00288 {
00289         "A",     1,  "a host address",
00290         "NS",    2,  "an authoritative name server",
00291         "MD",    3,  "a mail destination (Obsolete - use MX)",
00292         "MF",    4,  "a mail forwarder (Obsolete - use MX)",
00293         "CNAME", 5,  "the canonical name for an alias",
00294         "SOA",   6,  "marks the start of a zone of authority",
00295         "MB",    7,  "a mailbox domain name (EXPERIMENTAL)",
00296         "MG",    8,  "a mail group member (EXPERIMENTAL)",
00297         "MR",    9,  "a mail rename domain name (EXPERIMENTAL)",
00298         "NULL",  10, "a null RR (EXPERIMENTAL)",
00299         "WKS",   11, "a well known service description",
00300         "PTR",   12, "a domain name pointer",
00301         "HINFO", 13, "host information",
00302         "MINFO", 14, "mailbox or mail list information",
00303         "MX",    15, "mail exchange",
00304         "TXT",   16, "text strings",
00305         "AXFR",  252, "qtype: A request for a transfer of an entire zone",
00306         "MAILB", 253, "qtype: A request for mailbox-related records (MB, MG or MR)",
00307         "MAILA", 254, "qtype: A request for mail agent RRs (Obsolete - see MX)",
00308         "*",     255, "qtype: A request for all records",
00309         0,       0,  0
00310 };
00311 
00312 struct ClassType
00313 {
00314         char *name;
00315         int value;
00316         char *description;
00317 };
00318         
00319 static ClassType class_types[] =
00320 {
00321         "IN",    1,   "the Internet",
00322         "CS",    2,   "the CSNET class (Obsolete)",
00323         "CH",    3,   "the CHAOS class",
00324         "HS",    4,   "Hesiod [Dyer 87]",
00325         "*",     255, "qclass: Any class",
00326         0,       0,   0
00327 };
00328 
00329 int CL_DNSResourceRecord::type_to_int(const CL_String &qtype)
00330 {
00331         CL_StringA qtype_local8 = CL_StringHelp::text_to_local8(qtype);
00332         for (int index = 0; rr_types[index].name != 0; index++)
00333         {
00334                 if (rr_types[index].name == qtype_local8)
00335                         return rr_types[index].value;
00336         }
00337         
00338         int value = CL_StringHelp::local8_to_int(qtype_local8);
00339         if (value <= 0)
00340                 throw CL_Exception(TEXT("Unknown DNS resource record type ") + qtype);
00341         return value;
00342 }
00343 
00344 CL_String CL_DNSResourceRecord::type_from_int(int qtype)
00345 {
00346         for (int index = 0; rr_types[index].name != 0; index++)
00347         {
00348                 if (rr_types[index].value == qtype)
00349                         return CL_StringHelp::local8_to_text(rr_types[index].name);
00350         }
00351         return CL_StringHelp::int_to_text(qtype);
00352 }
00353 
00354 CL_String CL_DNSResourceRecord::type_description(const CL_String &qtype)
00355 {
00356         CL_StringA qtype_local8 = CL_StringHelp::text_to_local8(qtype);
00357         for (int index = 0; rr_types[index].name != 0; index++)
00358         {
00359                 if (rr_types[index].name == qtype_local8)
00360                         return CL_StringHelp::local8_to_text(rr_types[index].description);
00361         }
00362         return TEXT("Unknown type ") + qtype;
00363 }
00364 
00365 CL_String CL_DNSResourceRecord::type_description(int qtype)
00366 {
00367         for (int index = 0; rr_types[index].name != 0; index++)
00368         {
00369                 if (rr_types[index].value == qtype)
00370                         return CL_StringHelp::local8_to_text(rr_types[index].description);
00371         }
00372         return TEXT("Unknown type ") + CL_StringHelp::int_to_text(qtype);
00373 }
00374 
00375 int CL_DNSResourceRecord::class_to_int(const CL_String &qclass)
00376 {
00377         CL_StringA qclass_local8 = CL_StringHelp::text_to_local8(qclass);
00378         for (int index = 0; class_types[index].name != 0; index++)
00379         {
00380                 if (class_types[index].name == qclass_local8)
00381                         return class_types[index].value;
00382         }
00383         
00384         int value = CL_StringHelp::local8_to_int(qclass_local8);
00385         if (value <= 0)
00386                 throw CL_Exception(TEXT("Unknown DNS resource record type ") + qclass);
00387         return value;
00388 }
00389 
00390 CL_String CL_DNSResourceRecord::class_from_int(int qclass)
00391 {
00392         for (int index = 0; class_types[index].name != 0; index++)
00393         {
00394                 if (class_types[index].value == qclass)
00395                         return CL_StringHelp::local8_to_text(class_types[index].name);
00396         }
00397         return CL_StringHelp::int_to_text(qclass);
00398 }
00399 
00400 CL_String CL_DNSResourceRecord::class_description(const CL_String &qclass)
00401 {
00402         CL_StringA qclass_local8 = CL_StringHelp::text_to_local8(qclass);
00403         for (int index = 0; class_types[index].name != 0; index++)
00404         {
00405                 if (class_types[index].name == qclass_local8)
00406                         return CL_StringHelp::local8_to_text(class_types[index].description);
00407         }
00408         return TEXT("Unknown class ") + qclass;
00409 }
00410 
00411 CL_String CL_DNSResourceRecord::class_description(int qclass)
00412 {
00413         for (int index = 0; class_types[index].name != 0; index++)
00414         {
00415                 if (class_types[index].value == qclass)
00416                         return CL_StringHelp::local8_to_text(class_types[index].description);
00417         }
00418         return TEXT("Unknown class ") + CL_StringHelp::int_to_text(qclass);
00419 }
00420 
00422 // CL_DNSResourceRecord Implementation:
00423 
00424 int CL_DNSResourceRecord::find_domain_name_end(const CL_ByteArray &packet, int offset)
00425 {
00426         const unsigned char *data = (const unsigned char *) packet.get_data();
00427         while (true)
00428         {
00429                 if (offset >= packet.get_size())
00430                         throw CL_Exception(TEXT("Premature end of resource data domain name"));
00431 
00432                 if (data[offset] > 0 && data[offset] < 64)
00433                 {
00434                         offset += data[offset] + 1;
00435                 }
00436                 else if ((data[offset] & 0xc0) == 0xc0)
00437                 {
00438                         offset += 2;
00439                         break;
00440                 }
00441                 else if (data[offset] == 0)
00442                 {
00443                         offset++;
00444                         break;
00445                 }
00446                 else
00447                 {
00448                         throw CL_Exception(TEXT("Malformed resource data domain name (find_domain_name_end)"));
00449                 }
00450         }
00451         return offset;
00452 }
00453         
00454 CL_String CL_DNSResourceRecord::read_domain_name(const CL_ByteArray &packet, int offset)
00455 {
00456         CL_String name;
00457         const unsigned char *data = (const unsigned char *) packet.get_data();
00458         while (true)
00459         {
00460                 if (offset >= packet.get_size())
00461                         throw CL_Exception(TEXT("Premature end of resource data domain name"));
00462                         
00463                 if (data[offset] > 0 && data[offset] < 64)
00464                 {
00465                         if (offset+1+data[offset] >= packet.get_size())
00466                                 throw CL_Exception(TEXT("Premature end of resource data domain name"));
00467                         
00468                         if (!name.empty())
00469                                 name.append(TEXT("."));
00470 
00471                         name.append(CL_StringHelp::local8_to_text(CL_StringA((const char *) data+offset+1, data[offset])));
00472                         offset += data[offset] + 1;
00473 
00474                         if (name.length() > 512)
00475                                 throw CL_Exception(TEXT("Domain name exceeds 512 characters!"));
00476                 }
00477                 else if ((data[offset] & 0xc0) == 0xc0)
00478                 {
00479                         if (offset+1 >= packet.get_size())
00480                                 throw CL_Exception(TEXT("Premature end of resource data domain name"));
00481                 
00482                         offset = (int(data[offset] & 0x3f) << 8) + data[offset+1];
00483                 }
00484                 else if (data[offset] == 0)
00485                 {
00486                         break;
00487                 }
00488                 else
00489                 {
00490                         throw CL_Exception(TEXT("Malformed resource data domain name"));
00491                 }
00492         }
00493         return name;
00494 }

Generated on Sat Feb 19 22:51:15 2005 for npcore by  doxygen 1.4.1