DNS协议与请求
win系統下, CMD中可以使用nslookup命令查看域名IP地址。
DNS服務器與客戶端通過帶有header和question的協議進行查詢與返回,其中header分為六項,分別為ID(會話標識),Flags(標志),questions(問題數),Answer RRs(回答資源記錄數),Authority RRs(授權 資源記錄數),Addition RRs(附加資源記錄數)。
1.header 填充函數
? ? ? ? 首先判斷輸入參數是否有效,對暫不使用的線束進行歸零處理。
struct dns_header {unsigned short id;unsigned short flags;unsigned short questions; unsigned short answer;unsigned short authority;unsigned short additional;};int dns_create_header(struct dns_header *header) {srandom(time(NULL));header->id = random();//1970年至今的秒數為范圍產生一個隨機數 為多線程不安全函數header->flags = htons(0x0100); //htons 為網絡字節轉換 將其轉換為相應格式header->questions = htons(1); //請求一個域名return 0;
}
? ? ? ? ?其中flags標志位分為以下位置(2字節)
? ? ? ? ?QR為查詢與響應標志,0查詢,1響應
? ? ? ? opcode 0表示標準查詢 1 反向查詢 2 服務器請求狀態
? ? ? ? AA表示授權回答?
? ? ? ? TC表示可截斷的
? ? ? ? RD表示期望遞歸
? ? ? ? RA表示可用遞歸
? ? ? ? rcode表示返回碼 0表示無差錯 3表示名字錯 2表示服務器錯誤
????????Questions、Answer RRs、Authority RRs、Additional RRs 各自 表示后面的四個區域的數目。Questions 表示查詢問題區域節的數量,Answers 表示回答區 域的數量,Authoritative namesversers 表示授權區域的數量,Additional recoreds 表示 附加區域的數量
2.問題創建
????????由以下四部分組成,查詢名 name,查詢類型 type,class 查詢類,length域名字節數
struct dns_question {int length;unsigned short qtype; //1 表示IPV4 地址 5 表示查詢規范域名unsigned short qclass; // 通常為1 表示inet數據unsigned char *name; //
};
其中,name 不定長字符串,且域名需要按照相應規范書寫。例如www.baidu.com應保存為3www5baidu3com0,末尾0不可省去。
int dns_create_question(struct dns_question *question, const char *hostname) {question->name = (char*)malloc(strlen(hostname) + 2);question->length = strlen(hostname) + 2;question->qtype = htons(1); question->qclass = htons(1);const char delim[2] = "."; //分隔符char *qname = question->name;char *hostname_dup = strdup(hostname); // 函數中存在一個malloc 進行復制一份需要對應freechar *token = strtok(hostname_dup, delim); //分割出第一段 wwwwhile (token != NULL) { //還沒分割結束size_t len = strlen(token); //長度*qname = len; //長度放入字符串qname ++;strncpy(qname, token, len+1); //字符串放入 +1可以使最后不需要單獨放一次0qname += len; //向后移位token = strtok(NULL, delim); //再次分割// 此處使用NULL 上次的tok還未結束,仍然tok的是hostname//如操作臨界資源 則為線程不安全函數}free(hostname_dup);}
? 3.數據發送
? ? ? ? 建立一個sockfd句柄
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET 表示協議組 SOCK_DGRAM表示數據報文方式
????????建立地址結構,其中sockaddr_in為發往服務器結構,約定俗成三項地址定義,歡迎抬杠知識老師原話。
struct sockaddr_in servaddr = {0}; //
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr(IP);
? ? ? ? 創建header、question并進行合并。request即為將字符串合為一個。
struct dns_header header = {0};
dns_create_header(&header);struct dns_question question = {0};
dns_create_question(&question, domain);char request[1024] = {0};
int length = dns_build_request(&header, &question, request, 1024);
? ? ? ? 數據發送,參數為sock句柄,發送的字符串,字符串長度,地址以及地址長度。
sendto(sockfd, request, length, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));
? ? ? ? 數據接收,參數與上一個函數基本相同。在response中即可查詢到相應IP地址。
struct sockaddr_in addr;size_t addr_len = sizeof(struct sockaddr_in);int n = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
4.UDP好處?
相較于TCP,UDP速度更快,不限下載帶寬,一人下載一屋子罵人,且響應速度快,多應用于游戲中
總結
- 上一篇: Keiichi Tsuchiya the
- 下一篇: 详细介绍四叉树 Quadtrees