Skip to content

Commit 074bd32

Browse files
committed
v1.0
0 parents  commit 074bd32

File tree

7 files changed

+537
-0
lines changed

7 files changed

+537
-0
lines changed

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 3.3)
2+
project(DNS)
3+
4+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
5+
6+
set(SOURCE_FILES main.cpp base/dns.cpp base/util.cpp)
7+
INCLUDE_DIRECTORIES(include)
8+
add_executable(DNS ${SOURCE_FILES})

README.md

Whitespace-only changes.

base/dns.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include "../include/dns.h"
2+
3+
//construct a binary datagram which is used to request the dns server.
4+
DNSMessage::DNSMessageData DNSMessage::toRequestData() {
5+
unsigned char data[4096];
6+
DNSHeader *newDNSHeader = reinterpret_cast<DNSHeader *> (data);
7+
//construct dns request header
8+
newDNSHeader->authorizationRecordCount = this->dnsHeader.authorizationRecordCount;
9+
newDNSHeader->descriptor = this->dnsHeader.descriptor;
10+
newDNSHeader->extraSourceCount = this->dnsHeader.extraSourceCount;
11+
newDNSHeader->questionCount = this->dnsHeader.questionCount;
12+
newDNSHeader->resourceRecourdCount = this->dnsHeader.resourceRecourdCount;
13+
newDNSHeader->flag = this->dnsHeader.flag;
14+
//construct queryQuestion Name of dns request
15+
16+
char *queryName = reinterpret_cast<char *>(&data[sizeof(DNSHeader)]);
17+
size_t queryNameLength = strlen((const char *) dnsQuestion.queryName);
18+
memcpy(queryName, dnsQuestion.queryName, queryNameLength);//copy query name
19+
20+
//construct queryQuestion type of dns request
21+
DNSType *newDNSQuestion = reinterpret_cast<DNSType *>(&data[sizeof(DNSHeader) + queryNameLength + 1]);
22+
newDNSQuestion->type = dnsQuestion.type.type;
23+
newDNSQuestion->typeClass = dnsQuestion.type.typeClass;
24+
return DNSMessageData(new std::pair<unsigned char *, int>(data, 12 + queryNameLength + 1 + 4));
25+
}
26+
27+
28+
29+
30+
31+
// DNSQuestion* newDNSQuestion=reinterpret_cast<DNSQuestion*>(&data2[sizeof(DNSHeader)]);
32+
// using namespace std;
33+
// cout<<newDNSQuestion<<endl;
34+
//
35+
// cout<<&newDNSQuestion->queryName<<endl;
36+
// char* aaa=reinterpret_cast<char*>(&data2[sizeof(DNSHeader)]);
37+
// printf("%p\n",aaa);
38+
39+
//assign values to DNSQuestion is too complex work it done perfectly... try another way: encapsulate the type and class to a entity.
40+
// char* newDNSQuestion=reinterpret_cast<char*>(&data2[sizeof(DNSHeader)+queryNameLength+1]);
41+
// char* oldDNSQuestion=reinterpret_cast<char*>(((char*)&dnsQuestion)+8);
42+
// memcpy(newDNSQuestion,oldDNSQuestion,4);

base/util.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
2+
#include <cassert>
3+
#include "../include/util.h"
4+
#include <stdexcept>
5+
#include <netinet/in.h>
6+
#include "../include/dns.h"
7+
8+
void split(const std::string &str, char c, std::vector<std::string> &v) {
9+
if (str.size() == 0) {
10+
throw std::invalid_argument("parameter str is empty");
11+
}
12+
std::string::size_type i = 0;
13+
std::string::size_type j = str.find(c);
14+
15+
while (j != std::string::npos) {
16+
v.push_back(str.substr(i, j - i));
17+
i = ++j;
18+
j = str.find(c, j);
19+
}
20+
if (j == std::string::npos)
21+
v.push_back(str.substr(i, str.length()));
22+
}
23+
24+
25+
void constructQueryName(std::string &hostName, unsigned char *host) {
26+
if (hostName.size() == 0) {
27+
throw std::invalid_argument("parameter hostName is invalid.");
28+
}
29+
if (!host) {
30+
throw std::invalid_argument("parameter host is invalid.");
31+
}
32+
33+
std::vector<std::string> v;
34+
split(hostName, '.', v);
35+
hostName.clear();
36+
for_each(v.begin(), v.end(), [&hostName, &host](std::string &s) {
37+
*host = s.size();
38+
host++;
39+
memcpy(host, s.c_str(), s.size());
40+
host += s.size();
41+
});
42+
}
43+
44+
// client has the responsibility to ensure the correctnes of the length of queryName,because of 2 bytes after domain name field;
45+
std::string restoreQueryName(const unsigned char *domainName, size_t length) {
46+
if (!domainName) {
47+
throw std::invalid_argument("parameter queryName is null or empty.");
48+
}
49+
if(*domainName=='\0'||length==0){
50+
return std::string(".");
51+
}
52+
// assert(hostName);
53+
// assert(hostNameLength>2);
54+
55+
unsigned char newQueryName[length*2]={0};
56+
unsigned char *newHostPos = newQueryName;
57+
const unsigned char *hostPos = domainName;
58+
59+
while (hostPos != (domainName + length + 1)) {
60+
size_t count = *hostPos++;
61+
if(count>63){
62+
break;
63+
}
64+
if(count==0){
65+
*newHostPos++ = ' ';
66+
continue;
67+
}
68+
for (int i = 0; i < count; i++) {
69+
*newHostPos++ = *hostPos++;
70+
}
71+
*newHostPos++ = '.';
72+
}
73+
newHostPos='\0';
74+
return std::string((char*)newQueryName);
75+
}
76+
77+
bool isIPType(int type) {
78+
assert(type >= 1);
79+
if (type == 1) {
80+
return true;
81+
}
82+
return false;
83+
}
84+
85+
bool isCNAMEType(int type){
86+
assert(type >= 1);
87+
if (type == 5) {
88+
return true;
89+
}
90+
return false;
91+
}
92+
93+
//bool ValidateHostName( std::string hostName) {
94+
// if (hostName.size() > 63 || hostName.size() == 0) {
95+
// return false;
96+
// }
97+
// std::regex urlRegex("^(www.)?[a-z0-9\\-]+\\.(com|cn)$");
98+
// if(std::regex_match(hostName,urlRegex)){
99+
// return true;
100+
// }
101+
// return false;
102+
//}
103+
104+
105+
void fillDNSQuestion(std::string &hostName, QueryType queryType, DNSQuestion &dnsQuestion) {
106+
assert(hostName.size() > 0);
107+
constructQueryName(hostName, dnsQuestion.queryName);
108+
//dnsQuestion.queryName="3www5baidu3com";
109+
dnsQuestion.type.typeClass = htons(1);//used to be 1, a internet address.
110+
dnsQuestion.type.type = htons(queryType);
111+
}
112+
113+
void fillDNSHeaeder(DNSHeader &header) {
114+
header.descriptor = htons(9);//a magic number...
115+
header.questionCount = htons(1);
116+
header.resourceRecourdCount = 0;
117+
header.authorizationRecordCount = 0;
118+
header.extraSourceCount = 0;
119+
120+
header.flag.QR = 0;// indicate that the message is used to request
121+
header.flag.OPCODE = 0;//standard query
122+
header.flag.AA = 1;//authoritative answer
123+
header.flag.TC = 0;//can be truncated or not
124+
header.flag.RD = 1;//tell the dns server that this query must be handled and the method is 'recursive'
125+
header.flag.RA = 1;//if dns server's query method is 'recursive', asign it 1
126+
header.flag.ZERO = 0;//it must be 0
127+
header.flag.RCODE = 0;//returned and assigned by dns server
128+
}
129+
130+
void fillDNSRequest(std::string &hostName, QueryType queryType, DNSMessage &dnsMesssage) {
131+
132+
assert(hostName.size() > 0);
133+
134+
fillDNSHeaeder(dnsMesssage.dnsHeader);
135+
fillDNSQuestion(hostName, queryType, dnsMesssage.dnsQuestion);
136+
}

include/dns.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#ifndef _DNS_INCLUDE
2+
#define _DNS_INCLUDE
3+
4+
#include <memory>
5+
#include <cstring>
6+
7+
enum QueryType {
8+
A = 1,
9+
PTR = 12
10+
};
11+
struct DNSFlag {
12+
unsigned char RD:1;
13+
unsigned char TC:1;
14+
unsigned char AA:1;
15+
unsigned char OPCODE:4;
16+
unsigned char QR:1;
17+
unsigned char RCODE:4;
18+
unsigned char ZERO:3;
19+
unsigned char RA:1;
20+
// unsigned char QR:1;
21+
// unsigned char OPCODE:4;
22+
// unsigned char AA:1;
23+
// unsigned char TC:1;
24+
// unsigned char RD:1;
25+
// unsigned char RA:1;
26+
// unsigned char ZERO:3;
27+
// unsigned char RCODE:4;
28+
};
29+
struct DNSHeader {
30+
unsigned short descriptor;
31+
DNSFlag flag;
32+
unsigned short questionCount;
33+
unsigned short resourceRecourdCount;
34+
unsigned short authorizationRecordCount;
35+
unsigned short extraSourceCount;
36+
};
37+
struct DNSType {
38+
unsigned short type;
39+
unsigned short typeClass;
40+
};
41+
42+
struct DNSQuestion {
43+
unsigned char queryName[4096];
44+
DNSType type;
45+
// unsigned short queryType=QueryType::A;
46+
// unsigned short queryClass=1;
47+
};
48+
49+
struct DNSMessage {
50+
typedef std::shared_ptr<std::pair<unsigned char *, int>> DNSMessageData;
51+
DNSHeader dnsHeader;
52+
DNSQuestion dnsQuestion;
53+
54+
DNSMessageData toRequestData();
55+
};
56+
57+
struct DNSResourceExtraInfo {
58+
DNSType type;
59+
int liveTime;
60+
unsigned short resourceDataLength;
61+
};
62+
63+
struct DNSResourceRecord {
64+
char domainName[4096];
65+
DNSResourceExtraInfo extraInfo;
66+
char dataResrouce[4096];
67+
};
68+
69+
70+
#endif

include/util.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
#ifndef DNS_UTILITY_H
3+
#define DNS_UTILITY_H
4+
5+
#include <string>
6+
#include <vector>
7+
#include <algorithm>
8+
#include <cstring>
9+
#include <netinet/in.h>
10+
#include "../include/dns.h"
11+
12+
void split(const std::string &s, char c, std::vector<std::string> &v);
13+
14+
//when constructing dns query name, using a byte to store the count of the query name, not char!
15+
//note that because of the validation of hostName , so we can assume that hostName if valid.
16+
void constructQueryName(std::string &hostName, unsigned char *host);
17+
18+
//restore the query name, for example , 3www5baidu3com -> www.baidu.com
19+
std::string restoreQueryName(const unsigned char *queryName, size_t length);
20+
21+
//indicating current whether the dns response type is IP or not
22+
bool isIPType(int type);
23+
24+
bool isCNAMEType(int type);
25+
26+
//bool ValidateHostName(std::string hostName);
27+
28+
29+
void fillDNSQuestion(std::string &hostName, QueryType queryType, DNSQuestion &dnsQuestion);
30+
31+
void fillDNSHeaeder(DNSHeader &header);
32+
33+
void fillDNSRequest(std::string &hostName, QueryType queryType, DNSMessage &dnsMesssage);
34+
35+
36+
37+
#endif

0 commit comments

Comments
 (0)