柚子快報(bào)邀請(qǐng)碼778899分享:網(wǎng)絡(luò) DNS和UDP編程的實(shí)現(xiàn)
柚子快報(bào)邀請(qǐng)碼778899分享:網(wǎng)絡(luò) DNS和UDP編程的實(shí)現(xiàn)
1.DNS的報(bào)文頭部格式
2.wireshark的顯示
在抓以太網(wǎng)包之后,通過(guò)篩選DNS并停止抓包,雙擊一個(gè)包,有:
圖1中從上到下,依次是物理層,鏈路層,網(wǎng)絡(luò)層,傳輸層和應(yīng)用層。
Domain Name System和圖一對(duì)應(yīng),并且request包和對(duì)應(yīng)的response包的Transcation ID是一樣的。
In表示internat,代號(hào)為1 。
3.c代碼實(shí)現(xiàn)
Query? name的格式:
在查找域名時(shí),使用類似哈夫曼樹的方式。以0為根,然后查找w,然后w,然后w。以此類推。
定義頭部和Query數(shù)據(jù)結(jié)構(gòu):
typedef struct DNS_header {
?? ?unsigned short ID;
?? ?unsigned short Flags;
?? ?unsigned short Questions;
?? ?unsigned short Answer;
?? ?unsigned short Authority;
?? ?unsigned short Addtional;
};
typedef struct Query {
?? ?int length;
?? ?unsigned short Type;
?? ?unsigned short Class;
char* name;
};
這里由于name長(zhǎng)度不確定,所以使用length和char*name;
創(chuàng)建header:
int Create_DNS_Header(DNS_header* header) {
if (!header)return -1;
memset(header, 0, sizeof(DNS_header));
srandom(time(NULL));
header->ID = random();
header->Questions = 1;
header->Flags = htons(0X0100);
return 0;
}
注意: ?? ?srandom(time(NULL));
? ? ?header->ID = random();
不是線程安全的,如果?srandom(time(NULL));后其他線程使用random(),則會(huì)重新在隨機(jī)種子中隨機(jī)。
?? ?header->Flags = htons(0X0100); 把大端和小端的存儲(chǔ)方式統(tǒng)一成網(wǎng)絡(luò)傳輸格式。
創(chuàng)建Query:
int Create_DNS_Query(Query* q, char* name) {
if (!q || !name)return -1;
memset(q, 0, sizeof(Query));
q->Type = htons(1);
q->Class = htons(1);
q->length = strlen(name) + 2;
char split = '.';
q->name = NULL;
char* token;
char* namedup = strdup(name);
token = strtok(name, split);
char* token_name = q->name;
while (token) {
size_t size = strlen(token);
*token_name = size;
token_name++;
strncpy(token_name, token, size+1);
token_name += size;
token = strtok(NULL, split);
}
free(namedup);
return 0;
}
strncpy后的size+1以及q- 注意: ? ? ? ? strtok會(huì)把結(jié)果保存,不是一個(gè)線程安全的函數(shù)。 所有的代碼(cpp): #include #include #include #include #include #include #include #include #include #include #define DNS_HOST 0x01 #define DNS_CNAME 0x05 #define DNSPORT 53 #define DNSIP "114.114.114.114" typedef struct DNS_Header { unsigned short ID; unsigned short Flags; unsigned short Questions; unsigned short Answer; unsigned short Authority; unsigned short Addtional; }; struct dns_item { char* domain; char* ip; }; typedef struct DNS_Query { int length; unsigned short Type; unsigned short Class; char* name; }; int Create_DNS_Header(DNS_Header* header) { if (!header)return -1; memset(header, 0, sizeof(DNS_Header)); srandom(time(NULL)); header->ID = random(); header->Questions = htons(1); header->Flags = htons(0X0100); return 0; } int Create_DNS_Query(DNS_Query* q, char* name) { if (!q || !name)return -1; memset(q, 0, sizeof(DNS_Query)); q->Type = htons(1); q->Class = htons(1); q->length = strlen(name) + 2; char split[2] = "."; q->name = (char*)malloc(strlen(name) + 2);; char* token; char* namedup = strdup(name); token = strtok(name, split); char* token_name = q->name; while (token) { size_t size = strlen(token); *token_name = size; token_name++; strncpy(token_name, token, size+1); token_name += size; token = strtok(NULL, split); } free(namedup); return 0; } int Bind_Header_Query(DNS_Query* query, DNS_Header* header, char* request) { size_t header_size = sizeof(DNS_Header); memcpy(request, header, header_size); size_t offset = header_size; memcpy(request+ offset, query->name, query->length); offset += query->length; memcpy(request+ offset, &query->Type, sizeof(query->Type)); offset += sizeof(query->Type); memcpy(request+ offset, &query->Class, sizeof(query->Class)); offset += sizeof(query->Class); return offset; } static int is_pointer(int in) { return ((in & 0xC0) == 0xC0); } static void dns_parse_name(unsigned char* chunk, unsigned char* ptr, char* out, int* len) { int flag = 0, n = 0, alen = 0; char* pos = out + (*len); while (1) { flag = (int)ptr[0]; if (flag == 0) break; if (is_pointer(flag)) { n = (int)ptr[1]; ptr = chunk + n; dns_parse_name(chunk, ptr, out, len); break; } else { ptr++; memcpy(pos, ptr, flag); pos += flag; ptr += flag; *len += flag; if ((int)ptr[0] != 0) { memcpy(pos, ".", 1); pos += 1; (*len) += 1; } } } } static int dns_parse_response(char* buffer, struct dns_item** domains) { int i = 0; unsigned char* ptr = (unsigned char*)buffer; ptr += 4; int querys = ntohs(*(unsigned short*)ptr); ptr += 2; int answers = ntohs(*(unsigned short*)ptr); ptr += 6; for (i = 0; i < querys; i++) { while (1) { int flag = (int)ptr[0]; ptr += (flag + 1); if (flag == 0) break; } ptr += 4; } char cname[128], aname[128], ip[20], netip[4]; int len, type, ttl, datalen; int cnt = 0; struct dns_item* list = (struct dns_item*)calloc(answers, sizeof(struct dns_item)); if (list == NULL) { return -1; } for (i = 0; i < answers; i++) { bzero(aname, sizeof(aname)); len = 0; dns_parse_name((unsigned char*)buffer, ptr, aname, &len); ptr += 2; type = htons(*(unsigned short*)ptr); ptr += 4; ttl = htons(*(unsigned short*)ptr); ptr += 4; datalen = ntohs(*(unsigned short*)ptr); ptr += 2; if (type == DNS_CNAME) { bzero(cname, sizeof(cname)); len = 0; dns_parse_name((unsigned char*)buffer, ptr, cname, &len); ptr += datalen; } else if (type == DNS_HOST) { bzero(ip, sizeof(ip)); if (datalen == 4) { memcpy(netip, ptr, datalen); inet_ntop(AF_INET, netip, ip, sizeof(struct sockaddr)); printf("%s has address %s\n", aname, ip); printf("\tTime to live: %d minutes , %d seconds\n", ttl / 60, ttl % 60); list[cnt].domain = (char*)calloc(strlen(aname) + 1, 1); memcpy(list[cnt].domain, aname, strlen(aname)); list[cnt].ip = (char*)calloc(strlen(ip) + 1, 1); memcpy(list[cnt].ip, ip, strlen(ip)); cnt++; } ptr += datalen; } } *domains = list; ptr += 2; return cnt; } int Send_Client_Commit(char* domain) { int out = socket(AF_INET, SOCK_DGRAM, 0); if (out < 0) { printf("Socket error: %s\n", strerror(errno)); return -1; } sockaddr_in skaddr = { 0 }; skaddr.sin_family = AF_INET; skaddr.sin_port = htons(DNSPORT); skaddr.sin_addr.s_addr = inet_addr(DNSIP); DNS_Query query = { 0 }; DNS_Header header = { 0 }; int ret = Create_DNS_Query(&query, domain); if (ret) { return -2; } ret = Create_DNS_Header(&header); if (ret) { return -3; } connect(out, (struct sockaddr*)&skaddr, sizeof(sockaddr_in)); char request[1024] = { 0 }; int length = Bind_Header_Query(&query, &header, request); if (length<0) { return -4; } int size = sizeof(sockaddr); ret = sendto(out, request, length, 0, (struct sockaddr*)&skaddr, sizeof(struct sockaddr)); if (ret==-1) { return -5; } char response[1024] = { 0 }; sockaddr_in add; size_t addr_len = sizeof(struct sockaddr_in); ret = recvfrom(out, response, sizeof(response), 0, (struct sockaddr*)&add, (socklen_t*)&addr_len); struct dns_item* dns_domain = NULL; dns_parse_response(response, &dns_domain); free(dns_domain); return 0; } int main(int argc, char* argv[]) { if (argc < 2) { printf("input error"); return -1; } Send_Client_Commit(argv[1]); return 0; } 柚子快報(bào)邀請(qǐng)碼778899分享:網(wǎng)絡(luò) DNS和UDP編程的實(shí)現(xiàn) 文章來(lái)源
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。