checks for server conductibility if user is root
| | |
| | | #include <netinet/in.h> |
| | | #include <netinet/ip.h> |
| | | #include <netinet/ip_icmp.h> |
| | | #include <netinet/udp.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | |
| | | 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) |
| | | { |
| | |
| | | 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)); |
| | | /* printf("%d, %s\n", r, strerror(errno)); */ |
| | | return -1; |
| | | } |
| | | setsockopt(r, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timespec)); |
| | |
| | | sizeof(struct QUESTION), |
| | | 0, (struct sockaddr*)&dest, sizeof(dest)); |
| | | |
| | | if (ret < 0) { |
| | | return 3; |
| | | } |
| | | |
| | | 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"); |
| | | if (ret < 0) { |
| | | /* printf("*2, %d, %s\n", ret, strerror(errno)); */ |
| | | break; |
| | | } |
| | | if ((ret = memcmp(&buf_send, buf + sizeof(struct ip) + sizeof(struct udphdr), sizeof(struct DNS_HEADER)))) { |
| | | 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) { |
| | | if (ip_head->ip_p != IPPROTO_UDP) { |
| | | if (ip_head->ip_p == IPPROTO_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; |
| | | } |
| | | } |
| | |
| | | // Variables are only modified before threads are created and as such are |
| | | // thread-safe tests_done is modified to provide a rough count of number of |
| | | // tests being completed for progress measurement |
| | | int tests_done = 0, num_tests = NUM_TESTS, num_servers = NUM_DNS, num_hosts = 0; |
| | | int tests_done = 0, num_tests = NUM_TESTS, num_servers = 0, num_hosts = 0; |
| | | struct hosts_list* hosts = NULL; |
| | | struct dns_list* servers = NULL; |
| | | |
| | |
| | | } |
| | | for (int i = 0; i < NUM_DNS; i++) { |
| | | add_dns_server(&servers, (char*)DNS_SERVERS[i]); |
| | | num_servers++; |
| | | } |
| | | test_dns(); |
| | | sort_servers(&servers); |
| | |
| | | { |
| | | struct dns_list* curr = servers; |
| | | int i = 0; |
| | | pthread_t* threads = malloc(num_servers * sizeof(pthread_t)); |
| | | int init_num_servers = num_servers; |
| | | pthread_t* threads; |
| | | pthread_t progress; |
| | | // Check each server for reachability, can't be done in parallel as incorrect packets are received |
| | | // reachable() requires raw packets, which needs root |
| | | if (getuid() == 0) { |
| | | while (curr) { |
| | | printf("\rTesting reachability: %d/%d", i, init_num_servers); fflush(stdout); |
| | | unsigned char* buf[65535]; |
| | | int error_count = 0; |
| | | curr->errors = 0; |
| | | // retry 10 times for UDP unreliability |
| | | for (int i = 0; i < 10; i++) { |
| | | error_count += (reachable((unsigned char*)buf, curr->server) != 0); |
| | | } |
| | | /* fprintf(stderr, "ip: %s, ec: %d\n", curr->server, error_count); */ |
| | | // 30% error rate means unreachable |
| | | if (error_count >= 3) { |
| | | curr->errors = -1; |
| | | num_servers--; |
| | | } |
| | | curr = curr->next; |
| | | i++; |
| | | } |
| | | printf("\rTesting reachability: %d/%d\n", i, init_num_servers); |
| | | } |
| | | |
| | | threads = malloc(num_servers * sizeof(pthread_t)); |
| | | curr = servers; |
| | | i = 0; |
| | | pthread_create(&progress, NULL, print_progress, NULL); |
| | | while (curr) { |
| | | pthread_create(&threads[i], NULL, test_server, (void*)curr); |
| | | if (curr->errors == 0) { |
| | | pthread_create(&threads[i], NULL, test_server, (void*)curr); |
| | | i++; |
| | | } |
| | | curr = curr->next; |
| | | i++; |
| | | } |
| | | for (int i = 0; i < num_servers; i++) { |
| | | pthread_join(threads[i], NULL); |
| | |
| | | struct dns_list* dns = (struct dns_list*)in; |
| | | dns->time.tv_sec = 0; |
| | | dns->time.tv_nsec = 0; |
| | | dns->errors = 0; |
| | | for (int i = 0; i < num_tests; i++) { |
| | | struct hosts_list* curr = hosts; |
| | | while (curr) { |
| | |
| | | |
| | | int print_servers(struct dns_list* head) |
| | | { |
| | | struct dns_list* curr = head; |
| | | printf("%-16s | %-11s | %s\n", "Server", "Time", "Errors"); |
| | | while (head) { |
| | | printf("%-16s | %ld.%09ld | %d\n", head->server, head->time.tv_sec, |
| | | head->time.tv_nsec, head->errors); |
| | | head = head->next; |
| | | while (curr) { |
| | | if (curr->errors != -1) { |
| | | printf("%-16s | %ld.%09ld | %d\n", curr->server, curr->time.tv_sec, |
| | | curr->time.tv_nsec, curr->errors); |
| | | } |
| | | curr = curr->next; |
| | | } |
| | | fflush(stdout); |
| | | curr = head; |
| | | if (head->errors == -1) { |
| | | printf("The following servers were unreachable:\n"); |
| | | while (curr && curr->errors == -1) { |
| | | printf("%s\n", curr->server); |
| | | curr = curr->next; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | |
| | | |
| | | int main(void) |
| | | { |
| | | char* hostname = "google.com"; |
| | | char* IP = "127.0.0.1"; |
| | | int type = T_A; |
| | | unsigned char buf[65536]; |
| | | struct timespec ret; |
| | | int r; |
| | | int error_count; |
| | | |
| | | r = reachable(buf, "10.0.0.0"); |
| | | printf("%d\n", r); |
| | | /* print_packet(buf + sizeof(struct ip)); */ |
| | | r = reachable(buf, "127.0.0.2"); |
| | | printf("%d\n", r); |
| | | |
| | | /* ret = resolve(buf, hostname, IP, type); */ |
| | | |
| | | /* printf("%ld, %ld\n", ret.tv_sec, ret.tv_nsec); */ |
| | | |
| | | /* print_packet(buf); */ |
| | | /* for (int i = 0; i < 98; i++) { */ |
| | | /* printf("%X", buf[i]); */ |
| | | /* } */ |
| | | error_count = 0; |
| | | for (int i = 0; i < 100; i++) { |
| | | error_count += (reachable(buf, "1.1.1.1") != 0); |
| | | } |
| | | printf("1.1.1.1: %d\n", error_count); |
| | | error_count = 0; |
| | | for (int i = 0; i < 100; i++) { |
| | | error_count += (reachable(buf, "192.168.0.101") != 0); |
| | | } |
| | | printf("192.168.0.101: %d\n", error_count); |
| | | error_count = 0; |
| | | for (int i = 0; i < 100; i++) { |
| | | error_count += (reachable(buf, "192.168.0.100") != 0); |
| | | } |
| | | printf("192.168.0.100: %d\n", error_count); |
| | | error_count = 0; |
| | | for (int i = 0; i < 100; i++) { |
| | | error_count += (reachable(buf, "129.146.153.226") != 0); |
| | | } |
| | | printf("129.146.153.226: %d\n", error_count); |
| | | } |