Fix alignment with clang-format
6 files modified
1 files added
New file |
| | |
| | | --- |
| | | BasedOnStyle: LLVM |
| | | IndentWidth: 4 |
| | | TabWidth: 4 |
| | | UseTab: AlignWithSpaces |
| | | AllowShortIfStatementsOnASingleLine: true |
| | | BreakBeforeBraces: Linux |
| | | PointerAlignment: Left |
| | | AllowShortIfStatementsOnASingleLine: true |
| | | IndentCaseBlocks: true |
| | | IndentCaseLabels: false |
| | | SortUsingDeclarations: true |
| | |
| | | #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]; |
| | | } |
| | |
| | | #define T_TXT 16 // Text record |
| | | #define T_AAAA 28 // IPv6 address |
| | | |
| | | 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); |
| | | void print_packet(unsigned char* buf); |
| | |
| | | * Tried to only use POSIX functions to ensure cross platform compatibility |
| | | **/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #include <pthread.h> |
| | | #include "dns.h" |
| | | #include "servers.h" |
| | | #include "slist.h" |
| | | #include <pthread.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #include <unistd.h> |
| | | |
| | | #define NUM_TESTS 10 |
| | | |
| | |
| | | void *print_progress(void *in); |
| | | |
| | | // All global variables as passing to threads in structs caused corruption |
| | | // 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 |
| | | // 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; |
| | | struct hosts_list *hosts = NULL; |
| | | struct dns_list *servers = NULL; |
| | |
| | | printf("Options:\n"); |
| | | printf("\t-s <server>\tadd a DNS server to be tested\n"); |
| | | printf("\t-a <hostname>\tadd a hostname to be tested\n"); |
| | | printf("\t-t <number>\tspecify the number of hostnames to be tested, capped at 50 + number manually added\n\t\t\tdefaults to test all available\n"); |
| | | printf("\t-n <number>\tspecify the number of tests to perform on each hostname\n\t\t\tdefaults to 10\n"); |
| | | printf( |
| | | "\t-t <number>\tspecify the number of hostnames to be tested, " |
| | | "capped at 50 + number manually added\n\t\t\tdefaults to test " |
| | | "all " |
| | | "available\n"); |
| | | printf( |
| | | "\t-n <number>\tspecify the number of tests to perform on each " |
| | | "hostname\n\t\t\tdefaults to 10\n"); |
| | | printf("\t-h\t\tShow this help\n"); |
| | | free_dns_list(&servers); |
| | | free_hosts_list(&hosts); |
| | |
| | | } |
| | | |
| | | // Test each dns server individually |
| | | // Each test runs in its own thread and results are written to the respective dns_list |
| | | // Each test runs in its own thread and results are written to the respective |
| | | // dns_list |
| | | int test_dns(void) |
| | | { |
| | | struct dns_list *curr = servers; |
| | |
| | | { |
| | | unsigned long long avg_nsec = 0; |
| | | struct dns_list *dns = (struct dns_list *)in; |
| | | dns->time.tv_sec = 0; dns->time.tv_nsec = 0; |
| | | dns->time.tv_sec = 0; |
| | | dns->time.tv_nsec = 0; |
| | | for (int i = 0; i < num_tests; i++) { |
| | | struct hosts_list *curr = hosts; |
| | | while (curr) { |
| | | struct timespec run; |
| | | run.tv_sec = -1; run.tv_nsec = 0; |
| | | run.tv_sec = -1; |
| | | run.tv_nsec = 0; |
| | | unsigned char buf[65536]; |
| | | for (int j = 0; j < 3 && run.tv_sec == -1; j++) { |
| | | run = resolve(buf, curr->server, dns->server, T_A); |
| | | } |
| | | if (run.tv_sec == -1) //if test has failed 3 times, set time taken to 3s as penalty |
| | | if (run.tv_sec == -1) // if test has failed 3 times, set time taken |
| | | // to 3s as penalty |
| | | run.tv_sec = 3; |
| | | dns->time.tv_sec += run.tv_sec; |
| | | dns->time.tv_nsec += run.tv_nsec; |
| | | if (dns->time.tv_nsec >= 1000000000) { //nanoseconds have overflowed into seconds |
| | | if (dns->time.tv_nsec >= |
| | | 1000000000) { // nanoseconds have overflowed into seconds |
| | | dns->time.tv_sec += 1; |
| | | dns->time.tv_nsec -= 1000000000; |
| | | } |
| | |
| | | curr = curr->next; |
| | | } |
| | | } |
| | | avg_nsec = 1000000000*(dns->time.tv_sec%(num_hosts*num_tests))+dns->time.tv_nsec; |
| | | avg_nsec = 1000000000 * (dns->time.tv_sec % (num_hosts * num_tests)) + |
| | | dns->time.tv_nsec; |
| | | dns->time.tv_sec = dns->time.tv_sec/(num_hosts*num_tests); |
| | | dns->time.tv_nsec = avg_nsec/(num_hosts*num_tests); |
| | | return NULL; |
| | | } |
| | | |
| | | // Prints the progress every 0.1s for an indication of speed |
| | | // tests_done is being written to in parallel, so may be overwritten but serves as a decent estimate of the progress |
| | | // tests_done is being written to in parallel, so may be overwritten but serves |
| | | // as a decent estimate of the progress |
| | | void *print_progress(void *in) |
| | | { |
| | | struct timespec s; |
| | | s.tv_sec = 0; s.tv_nsec = 100000000; |
| | | s.tv_sec = 0; |
| | | s.tv_nsec = 100000000; |
| | | while (1) { |
| | | printf("\r%.2f%% done", ((float)tests_done)/(num_servers*num_hosts*num_tests) * 100); |
| | | printf("\r%.2f%% done", ((float)tests_done) / |
| | | (num_servers * num_hosts * num_tests) * |
| | | 100); |
| | | fflush(stdout); |
| | | nanosleep(&s, NULL); |
| | | } |
| | |
| | | /** |
| | | * Unfortunately, wanting to make cross platform required static lists of hosts and dns servers |
| | | * At least until I think of a good way to do it |
| | | * Hosts came from alexa top 50 one day and dns are from quick searching for common servers |
| | | * DNS only takes IPv4 server addresses |
| | | * The definitions must be the same as the size of the arrays, as they are required later on to be read properly |
| | | * Unfortunately, wanting to make cross platform required static lists of hosts |
| | | *and dns servers At least until I think of a good way to do it Hosts came from |
| | | *alexa top 50 one day and dns are from quick searching for common servers DNS |
| | | *only takes IPv4 server addresses The definitions must be the same as the size |
| | | *of the arrays, as they are required later on to be read properly |
| | | **/ |
| | | |
| | | #define NUM_HOSTNAMES 50 |
| | |
| | | #include "slist.h" |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include "slist.h" |
| | | |
| | | void split(struct dns_list *head, struct dns_list **a, struct dns_list **b); |
| | | struct dns_list *merge(struct dns_list *a, struct dns_list *b); |
| | |
| | | } |
| | | end->next = NULL; |
| | | end->server = server; |
| | | end->time.tv_nsec = 0; end->time.tv_sec = 0; |
| | | end->time.tv_nsec = 0; |
| | | end->time.tv_sec = 0; |
| | | return 0; |
| | | } |
| | | |
| | |
| | | struct dns_list *merge(struct dns_list *a, struct dns_list *b) |
| | | { |
| | | struct dns_list *out = NULL; |
| | | if (!a) |
| | | return b; |
| | | if (!b) |
| | | return a; |
| | | if (!a) return b; |
| | | if (!b) return a; |
| | | |
| | | if (comp_times(a->time, b->time) > 0) { |
| | | out = b; |
| | |
| | | { |
| | | printf("%-20s | %s\n", "Server", "Time"); |
| | | while (head) { |
| | | printf("%-20s | %ld.%09ld\n", head->server, head->time.tv_sec, head->time.tv_nsec); |
| | | printf("%-20s | %ld.%09ld\n", head->server, head->time.tv_sec, |
| | | head->time.tv_nsec); |
| | | head = head->next; |
| | | } |
| | | return 0; |