From e76468266a677537f1dbbe76e81aa87be60c67e3 Mon Sep 17 00:00:00 2001 From: Joel Grunbaum <joelgrun@gmail.com> Date: Tue, 31 May 2022 09:40:08 +0000 Subject: [PATCH] Initial support for reachability --- dns.c | 90 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 90 insertions(+), 0 deletions(-) diff --git a/dns.c b/dns.c index fb89c3a..3708389 100644 --- a/dns.c +++ b/dns.c @@ -1,4 +1,6 @@ #include <arpa/inet.h> +#include <asm-generic/socket.h> +#include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -9,9 +11,12 @@ #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 @@ -64,6 +69,60 @@ 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, @@ -321,3 +380,34 @@ 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; +} -- Gitblit v1.10.0