diff --git a/Makefile.in b/Makefile.in index 1064c77cb..f76581e5c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -185,7 +185,7 @@ release-rpms: web: cd $(NMAPDEVDIR) && $(MAKE) web -clean: @LUA_CLEAN@ @LIBLINEAR_CLEAN@ @PCAP_CLEAN@ @PCRE_CLEAN@ @DNET_CLEAN@ nsock_clean nbase_clean netutil_clean my_clean @NPING_CLEAN@ @ZENMAP_CLEAN@ @NCAT_CLEAN@ @NMAP_UPDATE_CLEAN@ @NDIFF_CLEAN@ +clean: @LUA_CLEAN@ @LIBLINEAR_CLEAN@ @PCAP_CLEAN@ @PCRE_CLEAN@ @DNET_CLEAN@ nsock_clean nbase_clean netutil_clean my_clean @NPING_CLEAN@ @ZENMAP_CLEAN@ @NCAT_CLEAN@ @NMAP_UPDATE_CLEAN@ @NDIFF_CLEAN@ tests/clean my_clean: rm -f dependencies.mk @@ -300,6 +300,9 @@ nmap-update/default_channel.h: nmap.h tests/check_dns: $(OBJS) $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ $(LIBS) tests/nmap_dns_test.cc +tests/clean: + @rm -f tests/check_dns + # By default distutils rewrites installed scripts to hardcode the # location of the Python interpreter they were built with (something # like #!/usr/bin/python2.4). This is the wrong thing to do when diff --git a/nmap_dns.cc b/nmap_dns.cc index 8b310d131..a596a873e 100644 --- a/nmap_dns.cc +++ b/nmap_dns.cc @@ -1477,29 +1477,31 @@ size_t DNS::Factory::putDomainName(const std::string &name, char *buf, size_t of return ret; } -size_t DNS::Factory::parseUnsignedShort(u16 &num, char *buf, size_t offset, size_t maxlen) +size_t DNS::Factory::parseUnsignedShort(u16 &num, const char *buf, size_t offset, size_t maxlen) { size_t max_access = offset+1; if(buf && (maxlen > max_access)) { - num = buf[max_access] + (buf[offset]<<8); + const u8 * n = reinterpret_cast(buf+offset); + num = n[1] + (n[0]<<8); return 2; } return 0; } -size_t DNS::Factory::parseUnsignedInt(u32 &num, char *buf, size_t offset, size_t maxlen) +size_t DNS::Factory::parseUnsignedInt(u32 &num, const char *buf, size_t offset, size_t maxlen) { size_t max_access = offset+3; if(buf && (maxlen > max_access)) { - num = buf[offset+3] + (buf[offset+2]<<8) + (buf[offset+1]<<16) + (buf[offset]<<24); + const u8 * n = reinterpret_cast(buf + offset); + num = n[3] + (n[2]<<8) + (n[1]<<16) + (n[0]<<24); return 4; } return 0; } -size_t DNS::Factory::parseDomainName(std::string &name, char *buf, size_t offset, size_t maxlen) +size_t DNS::Factory::parseDomainName(std::string &name, const char *buf, size_t offset, size_t maxlen) { size_t tmp, ret = 0; @@ -1537,7 +1539,7 @@ size_t DNS::Factory::parseDomainName(std::string &name, char *buf, size_t offset return ret; } -size_t DNS::Query::parseFromBuffer(char *buf, size_t offset, size_t maxlen) +size_t DNS::Query::parseFromBuffer(const char *buf, size_t offset, size_t maxlen) { size_t ret=0; @@ -1552,7 +1554,7 @@ size_t DNS::Query::parseFromBuffer(char *buf, size_t offset, size_t maxlen) return ret; } -size_t DNS::Answer::parseFromBuffer(char * buf, size_t offset, size_t maxlen) +size_t DNS::Answer::parseFromBuffer(const char * buf, size_t offset, size_t maxlen) { size_t ret=0; @@ -1570,21 +1572,26 @@ size_t DNS::Answer::parseFromBuffer(char * buf, size_t offset, size_t maxlen) switch(record_type) { + case A: + { + record = new A_Record(); + break; + } case CNAME: { record = new CNAME_Record(); - DNS_CHECK_ACCUMLATE(ret, tmp, record->parseFromBuffer(buf, offset+ret, maxlen)); break; } case PTR: { record = new PTR_Record(); - DNS_CHECK_ACCUMLATE(ret, tmp, record->parseFromBuffer(buf, offset+ret, maxlen)); break; } default: return 0; } + + DNS_CHECK_ACCUMLATE(ret, tmp, record->parseFromBuffer(buf, offset+ret, maxlen)); } return ret; @@ -1600,7 +1607,7 @@ DNS::Answer& DNS::Answer::operator=(const Answer &r) return *this; } -size_t DNS::Packet::parseFromBuffer(char *buf, size_t maxlen) +size_t DNS::Packet::parseFromBuffer(const char *buf, size_t maxlen) { if( !buf || maxlen < DATA) return 0; diff --git a/nmap_dns.h b/nmap_dns.h index 491899e6e..f5f673ab9 100644 --- a/nmap_dns.h +++ b/nmap_dns.h @@ -132,6 +132,7 @@ class Target; #include #include + namespace DNS { @@ -206,9 +207,9 @@ public: static size_t buildReverseRequest(const sockaddr_storage &ip, char *buf, size_t maxlen); static size_t putUnsignedShort(u16 num, char *buf, size_t offset, size_t maxlen); static size_t putDomainName(const std::string &name, char *buf, size_t offset, size_t maxlen); - static size_t parseUnsignedShort(u16 &num, char *buf, size_t offset, size_t maxlen); - static size_t parseUnsignedInt(u32 &num, char *buf, size_t offset, size_t maxlen); - static size_t parseDomainName(std::string &name, char *buf, size_t offset, size_t maxlen); + static size_t parseUnsignedShort(u16 &num, const char *buf, size_t offset, size_t maxlen); + static size_t parseUnsignedInt(u32 &num, const char *buf, size_t offset, size_t maxlen); + static size_t parseDomainName(std::string &name, const char *buf, size_t offset, size_t maxlen); }; class Record @@ -216,7 +217,28 @@ class Record public: virtual Record * clone() = 0; virtual ~Record() {} - virtual size_t parseFromBuffer(char *buf, size_t offset, size_t maxlen) = 0; + virtual size_t parseFromBuffer(const char *buf, size_t offset, size_t maxlen) = 0; +}; + +class A_Record : public Record +{ +public: + sockaddr_storage value; + Record * clone() { return new A_Record(*this); } + ~A_Record() {} + size_t parseFromBuffer(const char *buf, size_t offset, size_t maxlen) + { + size_t tmp, ret = 0; + u32 num; + DNS_CHECK_ACCUMLATE(ret, tmp, Factory::parseUnsignedInt(num, buf, offset, maxlen)); + + memset(&value, 0, sizeof(value)); + struct sockaddr_in * ip4addr = (sockaddr_in *) &value; + ip4addr->sin_family = AF_INET; + ip4addr->sin_addr.s_addr = htonl(num); + + return ret; + } }; class PTR_Record : public Record @@ -225,7 +247,7 @@ public: std::string value; Record * clone() { return new PTR_Record(*this); } ~PTR_Record() {} - size_t parseFromBuffer(char *buf, size_t offset, size_t maxlen) + size_t parseFromBuffer(const char *buf, size_t offset, size_t maxlen) { return Factory::parseDomainName(value, buf, offset, maxlen); } @@ -237,7 +259,7 @@ public: std::string value; Record * clone() { return new CNAME_Record(*this); } ~CNAME_Record() {} - size_t parseFromBuffer(char *buf, size_t offset, size_t maxlen) + size_t parseFromBuffer(const char *buf, size_t offset, size_t maxlen) { return Factory::parseDomainName(value, buf, offset, maxlen); } @@ -250,7 +272,7 @@ public: u16 record_type; u16 record_class; - size_t parseFromBuffer(char *buf, size_t offset, size_t maxlen); + size_t parseFromBuffer(const char *buf, size_t offset, size_t maxlen); }; class Answer @@ -270,7 +292,7 @@ public: Record * record; // Populate the object reading from buffer and returns "consumed" bytes - size_t parseFromBuffer(char * buf, size_t offset, size_t maxlen); + size_t parseFromBuffer(const char *buf, size_t offset, size_t maxlen); Answer& operator=(const Answer &r); }; @@ -284,7 +306,7 @@ public: void removeFlags(FLAGS fl){ flags &= ~fl; } void resetFlags() { flags = 0; } size_t writeToBuffer(char *buf, size_t maxlen); - size_t parseFromBuffer(char *buf, size_t maxlen); + size_t parseFromBuffer(const char *buf, size_t maxlen); u16 id; u16 flags; diff --git a/tests/nmap_dns_test.cc b/tests/nmap_dns_test.cc index 24d997449..c4031fec5 100644 --- a/tests/nmap_dns_test.cc +++ b/tests/nmap_dns_test.cc @@ -126,6 +126,9 @@ int main() { + std::cout << "Testing nmap_dns" << std::endl; + + int ret = 0; std::string target = "scanme.nmap.org"; DNS::RECORD_TYPE rt = DNS::A; const size_t buflen = 1500; @@ -135,5 +138,120 @@ int main() DNS::Packet p; size_t plen = p.parseFromBuffer(buf, buflen); - return (reqlen - plen); // 0 means ok + if (reqlen != plen) + { + std::cout << "ERROR: plen doesn't match reqplen" << std::endl; + ++ret; + } + + DNS::Query * q = &*p.queries.begin(); + if ( q->name != target ) + { + std::cout << "ERROR: q.name doesn't match target" << std::endl; + ++ret; + } + + if ( q->record_class != DNS::IN ) + { + std::cout << "ERROR: q.record_class doesn't match IN" << std::endl; + ++ret; + } + + if ( q->record_type != rt ) + { + std::cout << "ERROR: q.record_type doesn't match rt" << std::endl; + ++ret; + } + + // This is a possible answere for an A query for scanme.nmap.org + const char ipp[] = "45.33.32.156"; + const size_t answere_len = 49; + u8 answere_buf[] = { 0x92, 0xdc, // Trsnsaction ID + 0x81, 0x80, // Flags + 0x00, 0x01, // Questions count + 0x00, 0x01, // Answers RRs count + 0x00, 0x00, // Authorities RRs count + 0x00, 0x00, // Additionals RRs count + 0x06, // Label lenght <-- [12] + 0x73, 0x63, 0x61, 0x6e, 0x6d, 0x65, // "scanme" + 0x04, // Label lenght + 0x6e, 0x6d, 0x61, 0x70, // "nmap" + 0x03, // Label lenght + 0x6f, 0x72, 0x67, // "org" + 0x00, // Name terminator + 0x00, 0x01, // A + 0x00, 0x01, // IN + 0xc0, 0x0c, // Compressed name pointer to offset 12 + 0x00, 0x01, // A + 0x00, 0x01, // IN + 0x00, 0x00, 0x0e, 0x0f, // TTL 3599 + 0x00, 0x04, // Record Lenght + 0x2d, 0x21, 0x20, 0x9c }; // 45.33.32.156 + + plen = p.parseFromBuffer((char*)answere_buf, 49); + + if (answere_len != plen) + { + std::cout << "ERROR: plen doesn't match answere_len " << plen << std::endl; + ++ret; + } + + q = &*p.queries.begin(); + if ( q->name != target ) + { + std::cout << "ERROR: q.name doesn't match target" << std::endl; + ++ret; + } + + + if ( q->record_class != DNS::IN ) + { + std::cout << "ERROR: q.record_class doesn't match IN" << std::endl; + ++ret; + } + + if ( q->record_type != rt ) + { + std::cout << "ERROR: q.record_type doesn't match rt" << std::endl; + ++ret; + } + + DNS::Answer * a = &*p.answers.begin(); + if ( a->name != target ) + { + std::cout << "ERROR: a.name doesn't match target" << std::endl; + ++ret; + } + + if ( a->record_class != DNS::IN ) + { + std::cout << "ERROR: a.record_class doesn't match IN" << std::endl; + ++ret; + } + + if ( a->record_type != DNS::A ) + { + std::cout << "ERROR: a.record_type doesn't match rt" << std::endl; + ++ret; + } + + if (a->ttl != 3599 ) + { + std::cout << "ERROR: a.ttl doesn't match 3599 " << a->ttl << std::endl; + ++ret; + } + + DNS::A_Record * ar = static_cast(a->record); + char ar_ipp[INET6_ADDRSTRLEN]; + sockaddr_storage_iptop(&ar->value, ar_ipp); + if(strcmp(ipp, ar_ipp)) + { + std::cout << "ERROR: ar_ipp doesn't match ipp " << std::endl; + ++ret; + } + + if(ret) std::cout << "Testing nmap_dns finished with errors" << std::endl; + else std::cout << "Testing nmap_dns finished without errors" << std::endl; + + return ret; // 0 means ok }