| | |
| | | #include "dns.h" |
| | | #include <arpa/inet.h> |
| | | #include <asm-generic/socket.h> |
| | | #include <bits/time.h> |
| | | #include <errno.h> |
| | | #include <linux/if_ether.h> |
| | | #include <netinet/in.h> |
| | | #include <netinet/ip.h> |
| | | #include <netinet/ip_icmp.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <sys/socket.h> |
| | | //#include <netint/in.h> |
| | | //#include <netdb.h> |
| | | //#include <sys/time.h> |
| | | #include "dns.h" |
| | | #include <time.h> |
| | | #include <unistd.h> |
| | | |
| | | void change_to_DNS_name_format(unsigned char* dns, unsigned char* host); |
| | | char* read_name(unsigned char* reader, unsigned char* buffer, int* count); |
| | | int fill_DNS_data(unsigned char* buf, int datasize, char* hostname, |
| | | int query_type); |
| | | |
| | | // DNS code copied from |
| | | // https://gist.github.com/fffaraz/9d9170b57791c28ccda9255b48315168 |
| | |
| | | char* rdata; |
| | | }; |
| | | |
| | | #define IP_ICMP 1 |
| | | #define IP_TCP 6 |
| | | #define IP_UDP 17 |
| | | |
| | | // Test if an IP address is hosting a DNS server |
| | | int reachable(unsigned char* buf, char* dns_ip) |
| | | { |
| | | int s, r, ret, name_len; |
| | | struct sockaddr_in dest; |
| | | socklen_t dest_len = sizeof(dest); |
| | | struct timespec timeout, start, end; |
| | | struct icmphdr* icmp_head; |
| | | struct ip* ip_head; |
| | | unsigned char buf_send[65535]; |
| | | timeout.tv_sec = 1; |
| | | timeout.tv_nsec = 0; |
| | | |
| | | dest.sin_family = AF_INET; |
| | | dest.sin_port = htons(53); |
| | | dest.sin_addr.s_addr = inet_addr(dns_ip); |
| | | |
| | | s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| | | /* r = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); */ |
| | | r = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); |
| | | if (r < 0) { |
| | | printf("%d, %s\n", r, strerror(errno)); |
| | | return -1; |
| | | } |
| | | setsockopt(r, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timespec)); |
| | | |
| | | name_len = fill_DNS_data((unsigned char*)&buf_send, 65535, "google.com", T_A); |
| | | ret = sendto(s, buf_send, |
| | | sizeof(struct DNS_HEADER) + name_len + 1 + |
| | | sizeof(struct QUESTION), |
| | | 0, (struct sockaddr*)&dest, sizeof(dest)); |
| | | |
| | | clock_gettime(CLOCK_MONOTONIC, &start); |
| | | do { |
| | | ret = recvfrom(r, buf, 65535, 0, (struct sockaddr*)&dest, &dest_len); |
| | | clock_gettime(CLOCK_MONOTONIC, &end); |
| | | if (!memcmp(&buf_send, buf, 100)) { |
| | | printf("*1\n"); |
| | | break; |
| | | } |
| | | } while (start.tv_sec + 2 > end.tv_sec); |
| | | |
| | | close(s); |
| | | close(r); |
| | | |
| | | printf("diff: %d\n", memcmp(&buf_send, buf, 100)); |
| | | |
| | | ip_head = (struct ip*)buf; |
| | | icmp_head = (struct icmphdr*)buf + sizeof(struct ip); |
| | | |
| | | for (int i = 0; i < 93; i++) { |
| | | printf("%02X", buf[i]); |
| | | } |
| | | printf("\n"); |
| | | |
| | | printf("len: %d, ver: %d, tos: %d, tlen: %d, ident: %d, ff: %d, ttl: %d, " |
| | | "pro: %d, cs: %d, sip: %d, dip: %d\n", |
| | | ip_head->ip_hl, ip_head->ip_v, ip_head->ip_tos, ip_head->ip_len, |
| | | ip_head->ip_id, ip_head->ip_off, ip_head->ip_ttl, ip_head->ip_p, |
| | | ip_head->ip_sum, ip_head->ip_src.s_addr, ip_head->ip_dst.s_addr); |
| | | |
| | | if (ip_head->ip_p != IP_UDP) { |
| | | if (ip_head->ip_p == IP_ICMP) { |
| | | return 1; |
| | | } else { |
| | | printf("%d\n", ip_head->ip_p); |
| | | for (int i = 0; i < sizeof(struct ip); i++) { |
| | | printf("%02X", buf[i]); |
| | | } |
| | | printf("\n"); |
| | | return 2; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | // 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) |
| | | { |
| | | int s, i; |
| | | int s, i, name_len; |
| | | struct sockaddr_in dest; |
| | | unsigned char* qname; |
| | | struct DNS_HEADER* dns = (struct DNS_HEADER*)buf; |
| | | struct QUESTION* qinfo; |
| | | socklen_t dest_len = sizeof(dest); |
| | | struct timespec start, end, total, timeout; |
| | | timeout.tv_nsec = 0; |
| | | timeout.tv_sec = 1; |
| | |
| | | dest.sin_port = htons(53); |
| | | dest.sin_addr.s_addr = inet_addr(dns_ip); |
| | | |
| | | // dns packet header |
| | | dns->id = (unsigned short)htons(getpid()); |
| | | dns->qr = 0; // make query |
| | | dns->opcode = 0; // standard query |
| | | dns->aa = 0; // not authoritive |
| | | dns->tc = 0; // not trucated |
| | | dns->rd = 1; // want recursion |
| | | dns->ra = 0; // recursion not available |
| | | dns->z = 0; |
| | | dns->ad = 0; |
| | | dns->cd = 0; |
| | | dns->rcode = 0; |
| | | dns->q_count = htons(1); // one question |
| | | dns->ans_count = 0; |
| | | dns->auth_count = 0; |
| | | dns->add_count = 0; |
| | | |
| | | // 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->qclass = htons(1); // internet class |
| | | name_len = fill_DNS_data(buf, 65535, hostname, query_type); |
| | | |
| | | // 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 DNS_HEADER) + name_len + 1 + |
| | | sizeof(struct QUESTION), |
| | | 0, (struct sockaddr*)&dest, sizeof(dest)); |
| | | |
| | | if (i < 0) { |
| | | 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); |
| | | &dest_len); |
| | | clock_gettime(CLOCK_MONOTONIC, &end); |
| | | } |
| | | |
| | |
| | | name[i - 1] = '\0'; |
| | | return name; |
| | | } |
| | | |
| | | // Populate the sending DNS packet with data |
| | | int fill_DNS_data(unsigned char* buf, int datasize, char* hostname, |
| | | int query_type) |
| | | { |
| | | struct DNS_HEADER* dns = (struct DNS_HEADER*)buf; |
| | | struct QUESTION* qinfo; |
| | | unsigned char* qname; |
| | | |
| | | // dns packet header |
| | | dns->id = (unsigned short)htons(getpid()); |
| | | dns->qr = 0; // make query |
| | | dns->opcode = 0; // standard query |
| | | dns->aa = 0; // not authoritive |
| | | dns->tc = 0; // not trucated |
| | | dns->rd = 1; // want recursion |
| | | dns->ra = 0; // recursion not available |
| | | dns->z = 0; |
| | | dns->ad = 0; |
| | | dns->cd = 0; |
| | | dns->rcode = 0; |
| | | dns->q_count = htons(1); // one question |
| | | dns->ans_count = 0; |
| | | dns->auth_count = 0; |
| | | dns->add_count = 0; |
| | | |
| | | // 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->qclass = htons(1); // internet class |
| | | |
| | | return strlen((const char*)qname); |
| | | } |