| | |
| | | #include <arpa/inet.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <sys/socket.h> |
| | | #include <arpa/inet.h> |
| | | //#include <netint/in.h> |
| | | //#include <netdb.h> |
| | | //#include <sys/time.h> |
| | | #include "dns.h" |
| | | #include <time.h> |
| | | #include <unistd.h> |
| | | #include "dns.h" |
| | | |
| | | void change_to_DNS_name_format(unsigned char* dns, unsigned char* host); |
| | | char* read_name(unsigned char* reader, unsigned char* buffer, int* count); |
| | |
| | | // https://gist.github.com/fffaraz/9d9170b57791c28ccda9255b48315168 |
| | | |
| | | /* DNS header struct */ |
| | | struct DNS_HEADER |
| | | { |
| | | struct DNS_HEADER { |
| | | unsigned short id; //ID number |
| | | unsigned char rd :1; //recursion |
| | | unsigned char tc :1; //truncated message |
| | |
| | | }; |
| | | |
| | | /* structured for query structure */ |
| | | struct QUESTION |
| | | { |
| | | struct QUESTION { |
| | | unsigned short qtype; |
| | | unsigned short qclass; |
| | | }; |
| | | |
| | | /* Query structure */ |
| | | struct QUERY |
| | | { |
| | | struct QUERY { |
| | | unsigned char* name; |
| | | struct QUESTION* ques; |
| | | }; |
| | | |
| | | /* Constant sized fields of record structure */ |
| | | #pragma pack(push, 1) |
| | | struct R_DATA |
| | | { |
| | | struct R_DATA { |
| | | unsigned short type; |
| | | unsigned short _class; |
| | | unsigned int ttl; |
| | |
| | | #pragma pack(pop) |
| | | |
| | | /* Pointers to record components */ |
| | | struct RES_RECORD |
| | | { |
| | | struct RES_RECORD { |
| | | char* name; |
| | | struct R_DATA resource; |
| | | char* rdata; |
| | |
| | | |
| | | // Test server dns_ip as IPv4 string for hostname |
| | | // Writes received packet to buf, which is supplied and returns time for request |
| | | struct timespec resolve(unsigned char* buf, char* hostname, char* dns_ip, int query_type) |
| | | struct timespec resolve(unsigned char* buf, char* hostname, char* dns_ip, |
| | | int query_type) |
| | | { |
| | | int s, i; |
| | | struct sockaddr_in dest; |
| | |
| | | struct DNS_HEADER* dns = (struct DNS_HEADER*)buf; |
| | | struct QUESTION* qinfo; |
| | | struct timespec start, end, total, timeout; |
| | | timeout.tv_nsec=0; timeout.tv_sec=1; |
| | | timeout.tv_nsec = 0; |
| | | timeout.tv_sec = 1; |
| | | |
| | | s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| | | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timespec)); //use a 1 second timeout for receiving, should be more than enough and anything more is really bad |
| | | setsockopt( |
| | | s, SOL_SOCKET, SO_RCVTIMEO, &timeout, |
| | | sizeof(struct timespec)); // use a 1 second timeout for receiving, |
| | | // should be more than enough and anything |
| | | // more is really bad |
| | | dest.sin_family = AF_INET; |
| | | dest.sin_port = htons(53); |
| | | dest.sin_addr.s_addr = inet_addr(dns_ip); |
| | |
| | | //dns packet query |
| | | qname = (unsigned char*)&buf[sizeof(struct DNS_HEADER)]; |
| | | change_to_DNS_name_format(qname, (unsigned char*)hostname); |
| | | qinfo = (struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + strlen((const char*)qname) + 1]; |
| | | qinfo->qtype = htons(query_type); //type of query from argument (A,AAAA,MX,CNAME,NS,...) |
| | | qinfo = (struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + |
| | | strlen((const char*)qname) + 1]; |
| | | qinfo->qtype = htons( |
| | | query_type); // type of query from argument (A,AAAA,MX,CNAME,NS,...) |
| | | qinfo->qclass = htons(1); //internet class |
| | | |
| | | //send request |
| | | // return less than 0 is a fail |
| | | clock_gettime(CLOCK_MONOTONIC, &start); |
| | | i = sendto(s,(char*)buf, sizeof(struct DNS_HEADER)+strlen((const char*)qname)+1+sizeof(struct QUESTION), 0, (struct sockaddr*)&dest, sizeof(dest)); |
| | | i = sendto(s, (char*)buf, |
| | | sizeof(struct DNS_HEADER) + strlen((const char*)qname) + 1 + |
| | | sizeof(struct QUESTION), |
| | | 0, (struct sockaddr*)&dest, sizeof(dest)); |
| | | |
| | | if (i < 0) { |
| | | //receive response |
| | | //negative return is a fail |
| | | i = sizeof(dest); |
| | | i = recvfrom(s, (char*)buf, 65536, 0, (struct sockaddr*)&dest, (socklen_t*)&i); |
| | | i = recvfrom(s, (char*)buf, 65536, 0, (struct sockaddr*)&dest, |
| | | (socklen_t*)&i); |
| | | clock_gettime(CLOCK_MONOTONIC, &end); |
| | | } |
| | | |
| | |
| | | return total; |
| | | } |
| | | |
| | | // Print dns packet content, not terribly reliable but works for testing resolve with A requests |
| | | // Print dns packet content, not terribly reliable but works for testing resolve |
| | | // with A requests |
| | | void print_packet(unsigned char* buf) |
| | | { |
| | | struct RES_RECORD answers[20], auth[20], addit[20]; |
| | |
| | | unsigned char* qname = buf+sizeof(struct DNS_HEADER), *reader; |
| | | int stop, i, j; |
| | | dns = (struct DNS_HEADER*)buf; |
| | | reader = &buf[sizeof(struct DNS_HEADER)+strlen((const char*)qname)+1+sizeof(struct QUESTION)]; |
| | | printf("Response contains %d Qs, %d ans, %d auth serv, %d add reconds\n", ntohs(dns->q_count), ntohs(dns->ans_count), ntohs(dns->auth_count), ntohs(dns->add_count)); |
| | | reader = &buf[sizeof(struct DNS_HEADER) + strlen((const char*)qname) + 1 + |
| | | sizeof(struct QUESTION)]; |
| | | printf("Response contains %d Qs, %d ans, %d auth serv, %d add reconds\n", |
| | | ntohs(dns->q_count), ntohs(dns->ans_count), ntohs(dns->auth_count), |
| | | ntohs(dns->add_count)); |
| | | stop = 0; |
| | | |
| | | //read answers |
| | |
| | | reader = reader+sizeof(struct R_DATA); |
| | | |
| | | if (ntohs(answers[i].resource.type) == T_A) { //IPv4 address |
| | | answers[i].rdata = (char*)malloc(ntohs(answers[i].resource.data_len)); |
| | | answers[i].rdata = |
| | | (char*)malloc(ntohs(answers[i].resource.data_len)); |
| | | for (j = 0; j < ntohs(answers[i].resource.data_len); j++) { |
| | | answers[i].rdata[j] = reader[j]; |
| | | } |