| | |
| | | #include <arpa/inet.h> |
| | | #include <asm-generic/socket.h> |
| | | #include <netinet/in.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | |
| | | #include "dns.h" |
| | | #include <time.h> |
| | | #include <unistd.h> |
| | | #include <errno.h> |
| | | |
| | | void change_to_DNS_name_format(unsigned char* dns, unsigned char* host); |
| | | char* read_name(unsigned char* reader, unsigned char* buffer, int* count); |
| | | void fill_ICMP_data(unsigned char* icmp_data, int datasize); |
| | | unsigned short icmp_checksum(unsigned short* buf, int size); |
| | | |
| | | // DNS code copied from |
| | | // https://gist.github.com/fffaraz/9d9170b57791c28ccda9255b48315168 |
| | |
| | | char* rdata; |
| | | }; |
| | | |
| | | #define ICMP_ECHO 8 |
| | | #define ICMP_ECHOREPLY 0 |
| | | |
| | | struct ICMP_HEADER { |
| | | unsigned char type; |
| | | unsigned char code; |
| | | short checksum; |
| | | short id; |
| | | short seq; |
| | | long timestamp; |
| | | }; |
| | | |
| | | // Test if an IP address is hosting a DNS server |
| | | int reachable(unsigned char* buf, char* dns_ip) |
| | | { |
| | | int s, r; |
| | | int datasize = 64; |
| | | struct sockaddr_in dest; |
| | | struct timespec timeout; |
| | | 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); |
| | | |
| | | if (0) { |
| | | s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); |
| | | if (s < 0) { |
| | | printf("%d, %s\n", s, strerror(errno)); |
| | | return -1; |
| | | } |
| | | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timespec)); |
| | | |
| | | fill_ICMP_data(buf, datasize); |
| | | ((struct ICMP_HEADER*)buf)->checksum = icmp_checksum((unsigned short*)buf, datasize); |
| | | |
| | | r = sendto(s, buf, datasize, 0, (struct sockaddr*)&dest, sizeof(dest)); |
| | | printf("%d\n", r); |
| | | } |
| | | |
| | | s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| | | if (s < 0) { |
| | | printf("%d, %s\n", s, strerror(errno)); |
| | | return -1; |
| | | } |
| | | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timespec)); |
| | | |
| | | r = connect(s, (struct sockaddr*)&dest, sizeof(dest)); |
| | | printf("%d", r); |
| | | |
| | | return 1; |
| | | } |
| | | |
| | | // 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, |
| | |
| | | name[i - 1] = '\0'; |
| | | return name; |
| | | } |
| | | |
| | | // Populate the sending ICMP packet with data |
| | | void fill_ICMP_data(unsigned char* icmp_data, int datasize) |
| | | { |
| | | struct ICMP_HEADER* h = (struct ICMP_HEADER*)icmp_data; |
| | | unsigned char* d = icmp_data + sizeof(struct ICMP_HEADER); |
| | | |
| | | h->type = ICMP_ECHO; |
| | | h->code = 0; |
| | | h->id = getpid(); |
| | | h->checksum = 0; |
| | | h->seq = 0; |
| | | |
| | | memset(d, 'A', datasize - sizeof(struct ICMP_HEADER)); |
| | | } |
| | | |
| | | // Calculate the ICMP checksum |
| | | unsigned short icmp_checksum(unsigned short* buf, int size) |
| | | { |
| | | unsigned long checksum = 0; |
| | | while (size > 1) { |
| | | checksum += *buf++; |
| | | size -= sizeof(unsigned short); |
| | | } |
| | | if (size) { |
| | | checksum += *buf; |
| | | } |
| | | checksum = (checksum >> 16) + (checksum & 0xffff); |
| | | checksum += checksum >> 16; |
| | | return (unsigned short)~checksum; |
| | | } |