前面兩篇文章的一點應用-DNS
Packet header structureint InitSimpleDNS(void) dns_fd = socket(sockaddr.sin_family, SOCK_DGRAM, 0);//建立一個IPV4的socket,基於UDP資料套接字 ret = setsockopt(dns_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) ; //設定SO_REUSEADDR,呼叫closesocket(一般不會立即關閉而經歷TIME_WAIT的過程)後想繼續重用該socket: ret = bind(dns_fd, &sockaddr, sizeof(sockaddr)) ;//給socket返回值dns_fd,賦一個地址&sockaddr pthread_create( &pthrd_id,NULL,(void *) simple_dns_proc,NULL ))//建立一個執行緒simple_dns_proc static void *simple_dns_proc(void *handle) FD_ZERO(&dns_rset);//清空&dns_rset集合 get_answer_ip(&answer_addr); FD_SET(dns_fd, &dns_rset); //將一個給定的檔案描述符(dns_fd)加入集合(dns_rset)之中 ret = dns_rcv_query(&sockaddr); FD_CLR(dns_fd, &dns_rset);//將一個給定的檔案描述符從集合中刪除 dns_build_answer(header, &answer_len, &answer_addr); dns_send_answer((void*)header, answer_len, &sockaddr, &answer_addr); static int get_answer_ip(struct in_addr* ip_addr) strncpy(ifr.ifr_name, "rndis0", IF_NAMESIZE); ioctl(dns_fd, SIOCGIFADDR, &ifr);//獲取介面地址 static int dns_rcv_query(struct sockaddr_in* p_src_addr) select(dns_fd+1, &dns_rset, NULL, NULL, &timeout)//非阻塞,以返回值的不同來反映函式的執行情況,監視dns_rset的變化情況,有可讀返回大於0 FD_ISSET(dns_fd, &dns_rset)//檢查集合中指定的檔案描述符是否可以讀寫 iov[0].iov_base = dns_buf; //資料指標 iov[0].iov_len = DNS_BUF_SIZE; msg.msg_control = control_u.control;//附屬資料緩衝區 msg.msg_controllen = 0; msg.msg_flags = 0; //接收資訊標記位 msg.msg_name = p_src_addr; //套介面地址 msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_iov = iov; // I/O向量 msg.msg_iovlen = 1; recvmsg(dns_fd, &msg, 0) //從套接字上接收一個訊息 static int dns_build_answer(HEADER *header, unsigned short* answer_len, struct in_addr* answer_addr) p = (unsigned char *)(header+1) nameoffset = p - (unsigned char *)header; GETSHORT(qtype, p); //getshort函式從指定地址讀取16bit網路位元組順序的資料, 並將其轉換成little-endian的順序返回 GETSHORT(qclass, p); PUTSHORT(nameoffset | 0xc000, p); PUTSHORT(qtype, p); PUTSHORT(qclass, p); PUTLONG(0, p); /* TTL */ PUTSHORT(4, p); p += INADDRSZ; header->qr = 1; //* response */答覆 header->aa = 0; //* authoritive - only hosts and DHCP derived names. */權威,僅僅主機和DHCP衍生名 header->ra = 1; //* recursion if available */如果可獲取就遞迴查詢 header->tc = 0; //* truncation */截尾 header->rcode = NOERROR; /* no error */ header->ancount = htons(1);//將一個無符號短整型的主機數值轉換為網路位元組順序,即大尾順序(big-endian) header->nscount = htons(0);//header內容見下面圖文說明 header->arcount = htons(0); *answer_len = p -(unsigned char *)header; static int dns_send_answer(void* data, unsigned short data_len, struct sockaddr_in* to, struct in_addr* answer_addr) iov[0].iov_base = (void*)data; iov[0].iov_len = data_len; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; msg.msg_name = to; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_iov = iov; msg.msg_iovlen = 1; sendmsg(dns_fd, &msg, 0)//成功執行時,返回已傳送的位元組數。失敗返回-1
ID - A 16-bit identifier assigned by the program that generates any kind of query.
QR - Query/Response.
OPCODE - A 4-bit field that specifies the kind of query in this message. This value is set by the originator of a query and copied into the response. This specification defines the behavior of standard queries and responses (opcode value of zero). Future specifications may define the use of other opcodes with LLMNR.
C - Conflict.
TC - TrunCation.
T - Tentative.
Z - Reserved for future use.
RCODE - Response code.
QDCOUNT - An unsigned 16-bit integer specifying the number of entries in the question section.
ANCOUNT - An unsigned 16-bit integer specifying the number of resource records in the answer section.(資源記錄數)
NSCOUNT - An unsigned 16-bit integer specifying the number of name server resource records in the authority records section.(名稱伺服器資源記錄數)
ARCOUNT - An unsigned 16-bit integer specifying the number of resource records in the additional records section.(附加檔案記錄數)