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 |
| | | { |
| | | unsigned short id; //ID number |
| | | unsigned char rd :1; //recursion |
| | | unsigned char tc :1; //truncated message |
| | | unsigned char aa :1; //authoritive answer |
| | | unsigned char opcode :4; //message purpose |
| | | unsigned char qr :1; //query response |
| | | unsigned char rcode :4; //response code |
| | | unsigned char cd :1; //checking disabled |
| | | unsigned char ad :1; //authenticated data |
| | | unsigned char z :1; //reserved for future use |
| | | unsigned char ra :1; //recursion available |
| | | unsigned short q_count; //number of question entrise |
| | | unsigned short ans_count; //number of answer entries |
| | | unsigned short auth_count; //number of authority entries |
| | | unsigned short add_count; //number of resource entries |
| | | struct DNS_HEADER { |
| | | unsigned short id; // ID number |
| | | unsigned char rd : 1; // recursion |
| | | unsigned char tc : 1; // truncated message |
| | | unsigned char aa : 1; // authoritive answer |
| | | unsigned char opcode : 4; // message purpose |
| | | unsigned char qr : 1; // query response |
| | | unsigned char rcode : 4; // response code |
| | | unsigned char cd : 1; // checking disabled |
| | | unsigned char ad : 1; // authenticated data |
| | | unsigned char z : 1; // reserved for future use |
| | | unsigned char ra : 1; // recursion available |
| | | unsigned short q_count; // number of question entrise |
| | | unsigned short ans_count; // number of answer entries |
| | | unsigned short auth_count; // number of authority entries |
| | | unsigned short add_count; // number of resource entries |
| | | }; |
| | | |
| | | /* structured for query structure */ |
| | | struct QUESTION |
| | | { |
| | | unsigned short qtype; |
| | | unsigned short qclass; |
| | | struct QUESTION { |
| | | unsigned short qtype; |
| | | unsigned short qclass; |
| | | }; |
| | | |
| | | /* Query structure */ |
| | | struct QUERY |
| | | { |
| | | unsigned char* name; |
| | | struct QUESTION* ques; |
| | | struct QUERY { |
| | | unsigned char* name; |
| | | struct QUESTION* ques; |
| | | }; |
| | | |
| | | /* Constant sized fields of record structure */ |
| | | #pragma pack(push, 1) |
| | | struct R_DATA |
| | | { |
| | | unsigned short type; |
| | | unsigned short _class; |
| | | unsigned int ttl; |
| | | unsigned short data_len; |
| | | struct R_DATA { |
| | | unsigned short type; |
| | | unsigned short _class; |
| | | unsigned int ttl; |
| | | unsigned short data_len; |
| | | }; |
| | | #pragma pack(pop) |
| | | |
| | | /* Pointers to record components */ |
| | | struct RES_RECORD |
| | | { |
| | | char* name; |
| | | struct R_DATA resource; |
| | | char* rdata; |
| | | 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; |
| | | unsigned char *qname; |
| | | 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; |
| | | int s, i; |
| | | struct sockaddr_in dest; |
| | | unsigned char* qname; |
| | | 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; |
| | | |
| | | 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 |
| | | 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); |
| | | 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 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 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 |
| | | // 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 |
| | | |
| | | //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)); |
| | | // 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)); |
| | | |
| | | 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); |
| | | clock_gettime(CLOCK_MONOTONIC, &end); |
| | | } |
| | | 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); |
| | | clock_gettime(CLOCK_MONOTONIC, &end); |
| | | } |
| | | |
| | | // Make sure packet was returned |
| | | if (i == -1) |
| | | total.tv_nsec = -1; |
| | | else |
| | | total.tv_sec = end.tv_sec - start.tv_sec; |
| | | if ((end.tv_nsec - start.tv_nsec) < 0) |
| | | total.tv_nsec = start.tv_nsec - end.tv_nsec; |
| | | else |
| | | total.tv_nsec = end.tv_nsec - start.tv_nsec; |
| | | close(s); |
| | | return total; |
| | | // Make sure packet was returned |
| | | if (i == -1) |
| | | total.tv_nsec = -1; |
| | | else |
| | | total.tv_sec = end.tv_sec - start.tv_sec; |
| | | if ((end.tv_nsec - start.tv_nsec) < 0) |
| | | total.tv_nsec = start.tv_nsec - end.tv_nsec; |
| | | else |
| | | total.tv_nsec = end.tv_nsec - start.tv_nsec; |
| | | close(s); |
| | | 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]; |
| | | struct DNS_HEADER *dns; |
| | | struct sockaddr_in a; |
| | | 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)); |
| | | stop = 0; |
| | | struct RES_RECORD answers[20], auth[20], addit[20]; |
| | | struct DNS_HEADER* dns; |
| | | struct sockaddr_in a; |
| | | 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)); |
| | | stop = 0; |
| | | |
| | | //read answers |
| | | for (i = 0; i < ntohs(dns->ans_count); i++) { |
| | | answers[i].name = read_name(reader, buf, &stop); |
| | | reader = reader + stop; |
| | | memcpy(&(answers[i].resource), reader, sizeof(struct R_DATA)); |
| | | reader = reader+sizeof(struct R_DATA); |
| | | // read answers |
| | | for (i = 0; i < ntohs(dns->ans_count); i++) { |
| | | answers[i].name = read_name(reader, buf, &stop); |
| | | reader = reader + stop; |
| | | memcpy(&(answers[i].resource), reader, sizeof(struct R_DATA)); |
| | | 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)); |
| | | for (j = 0; j < ntohs(answers[i].resource.data_len); j++) { |
| | | answers[i].rdata[j] = reader[j]; |
| | | } |
| | | answers[i].rdata[ntohs(answers[i].resource.data_len)] = '\0'; |
| | | reader = reader + ntohs(answers[i].resource.data_len); |
| | | } else { |
| | | answers[i].rdata = read_name(reader, buf, &stop); |
| | | reader = reader + stop; |
| | | } |
| | | } |
| | | if (ntohs(answers[i].resource.type) == T_A) { // IPv4 address |
| | | 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]; |
| | | } |
| | | answers[i].rdata[ntohs(answers[i].resource.data_len)] = '\0'; |
| | | reader = reader + ntohs(answers[i].resource.data_len); |
| | | } else { |
| | | answers[i].rdata = read_name(reader, buf, &stop); |
| | | reader = reader + stop; |
| | | } |
| | | } |
| | | |
| | | //read authorities |
| | | for (i = 0; i < ntohs(dns->auth_count); i++) { |
| | | auth[i].name = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | memcpy(&(auth[i].resource), reader, sizeof(struct R_DATA)); |
| | | reader += sizeof(struct R_DATA); |
| | | auth[i].rdata = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | } |
| | | // read authorities |
| | | for (i = 0; i < ntohs(dns->auth_count); i++) { |
| | | auth[i].name = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | memcpy(&(auth[i].resource), reader, sizeof(struct R_DATA)); |
| | | reader += sizeof(struct R_DATA); |
| | | auth[i].rdata = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | } |
| | | |
| | | //read additional |
| | | for (i = 0; i < ntohs(dns->add_count); i++) { |
| | | addit[i].name = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | memcpy(&(addit[i].resource), reader, sizeof(struct R_DATA)); |
| | | reader += sizeof(struct R_DATA); |
| | | // read additional |
| | | for (i = 0; i < ntohs(dns->add_count); i++) { |
| | | addit[i].name = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | memcpy(&(addit[i].resource), reader, sizeof(struct R_DATA)); |
| | | reader += sizeof(struct R_DATA); |
| | | |
| | | if (ntohs(addit[i].resource.type) == 1) { |
| | | addit[i].rdata = malloc(ntohs(addit[i].resource.data_len)); |
| | | for (j = 0; j < ntohs(addit[i].resource.data_len); j++) |
| | | addit[i].rdata[j] = reader[j]; |
| | | addit[i].rdata[ntohs(addit[i].resource.data_len)] = '\0'; |
| | | reader += ntohs(addit[i].resource.data_len); |
| | | } else { |
| | | addit[i].rdata = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | } |
| | | } |
| | | if (ntohs(addit[i].resource.type) == 1) { |
| | | addit[i].rdata = malloc(ntohs(addit[i].resource.data_len)); |
| | | for (j = 0; j < ntohs(addit[i].resource.data_len); j++) |
| | | addit[i].rdata[j] = reader[j]; |
| | | addit[i].rdata[ntohs(addit[i].resource.data_len)] = '\0'; |
| | | reader += ntohs(addit[i].resource.data_len); |
| | | } else { |
| | | addit[i].rdata = read_name(reader, buf, &stop); |
| | | reader += stop; |
| | | } |
| | | } |
| | | |
| | | //print answers |
| | | printf("ans recs: %d\n", ntohs(dns->ans_count)); |
| | | for (i = 0; i < ntohs(dns->ans_count); i++) { |
| | | printf("name: %s ", answers[i].name); |
| | | if (ntohs(answers[i].resource.type) == T_A) { //IPv4 |
| | | long* p; |
| | | p = (long*)answers[i].rdata; |
| | | a.sin_addr.s_addr=(*p); |
| | | printf("has IPv4 addresss: %s", inet_ntoa(a.sin_addr)); |
| | | } else if (ntohs(answers[i].resource.type) == T_CNAME) { //CNAME |
| | | printf("has alias: %s", answers[i].rdata); |
| | | } |
| | | free(answers[i].name); |
| | | free(answers[i].rdata); |
| | | putc('\n', stdout); |
| | | } |
| | | // print answers |
| | | printf("ans recs: %d\n", ntohs(dns->ans_count)); |
| | | for (i = 0; i < ntohs(dns->ans_count); i++) { |
| | | printf("name: %s ", answers[i].name); |
| | | if (ntohs(answers[i].resource.type) == T_A) { // IPv4 |
| | | long* p; |
| | | p = (long*)answers[i].rdata; |
| | | a.sin_addr.s_addr = (*p); |
| | | printf("has IPv4 addresss: %s", inet_ntoa(a.sin_addr)); |
| | | } else if (ntohs(answers[i].resource.type) == T_CNAME) { // CNAME |
| | | printf("has alias: %s", answers[i].rdata); |
| | | } |
| | | free(answers[i].name); |
| | | free(answers[i].rdata); |
| | | putc('\n', stdout); |
| | | } |
| | | |
| | | //print authorities |
| | | printf("Auth recs: %d\n", ntohs(dns->auth_count)); |
| | | for (i = 0; i < ntohs(dns->auth_count); i++) { |
| | | printf("name: %s ", auth[i].name); |
| | | if (ntohs(auth[i].resource.type) == 1) { |
| | | long* p; |
| | | p = (long*)auth[i].rdata; |
| | | a.sin_addr.s_addr = *p; |
| | | printf("has IPv4 address: %s", inet_ntoa(a.sin_addr)); |
| | | } |
| | | free(answers[i].name); |
| | | free(auth[i].rdata); |
| | | putc('\n', stdout); |
| | | } |
| | | // print authorities |
| | | printf("Auth recs: %d\n", ntohs(dns->auth_count)); |
| | | for (i = 0; i < ntohs(dns->auth_count); i++) { |
| | | printf("name: %s ", auth[i].name); |
| | | if (ntohs(auth[i].resource.type) == 1) { |
| | | long* p; |
| | | p = (long*)auth[i].rdata; |
| | | a.sin_addr.s_addr = *p; |
| | | printf("has IPv4 address: %s", inet_ntoa(a.sin_addr)); |
| | | } |
| | | free(answers[i].name); |
| | | free(auth[i].rdata); |
| | | putc('\n', stdout); |
| | | } |
| | | |
| | | printf("Addit recs: %d\n", ntohs(dns->add_count)); |
| | | for (i = 0; i < ntohs(dns->add_count); i++) { |
| | | printf("name; %s", addit[i].name); |
| | | if (ntohs(auth[i].resource.type) == 1) { |
| | | long *p; |
| | | p = (long*)addit[i].rdata; |
| | | a.sin_addr.s_addr = *p; |
| | | printf("has IPv4 address: %s", inet_ntoa(a.sin_addr)); |
| | | } else { |
| | | printf("has %s", addit[i].rdata); |
| | | } |
| | | free(answers[i].name); |
| | | free(addit[i].rdata); |
| | | putc('\n', stdout); |
| | | } |
| | | printf("Addit recs: %d\n", ntohs(dns->add_count)); |
| | | for (i = 0; i < ntohs(dns->add_count); i++) { |
| | | printf("name; %s", addit[i].name); |
| | | if (ntohs(auth[i].resource.type) == 1) { |
| | | long* p; |
| | | p = (long*)addit[i].rdata; |
| | | a.sin_addr.s_addr = *p; |
| | | printf("has IPv4 address: %s", inet_ntoa(a.sin_addr)); |
| | | } else { |
| | | printf("has %s", addit[i].rdata); |
| | | } |
| | | free(answers[i].name); |
| | | free(addit[i].rdata); |
| | | putc('\n', stdout); |
| | | } |
| | | } |
| | | |
| | | // convert from dot format to dns format |
| | | // eg google.com to 6google3com |
| | | void change_to_DNS_name_format(unsigned char* dns, unsigned char* host) |
| | | { |
| | | int lock = 0; |
| | | char h[300]; |
| | | strcpy(h, (char*)host); |
| | | strcat((char*)h,"."); |
| | | int lock = 0; |
| | | char h[300]; |
| | | strcpy(h, (char*)host); |
| | | strcat((char*)h, "."); |
| | | |
| | | for (int i = 0; i < strlen(h); i++) { |
| | | if (h[i] == '.') { |
| | | *dns++ = i-lock; |
| | | for (;lock<i;lock++) { |
| | | *dns++ = h[lock]; |
| | | } |
| | | lock++; |
| | | } |
| | | } |
| | | *dns++ = '\0'; |
| | | for (int i = 0; i < strlen(h); i++) { |
| | | if (h[i] == '.') { |
| | | *dns++ = i - lock; |
| | | for (; lock < i; lock++) { |
| | | *dns++ = h[lock]; |
| | | } |
| | | lock++; |
| | | } |
| | | } |
| | | *dns++ = '\0'; |
| | | } |
| | | |
| | | // Convert from dns to dot format |
| | | char* read_name(unsigned char* reader, unsigned char* buffer, int* count) |
| | | { |
| | | char* name; |
| | | unsigned int p=0, jumped=0, offset; |
| | | int i, j; |
| | | *count = 1; |
| | | name = (char*)malloc(256); |
| | | name[0]='\0'; |
| | | char* name; |
| | | unsigned int p = 0, jumped = 0, offset; |
| | | int i, j; |
| | | *count = 1; |
| | | name = (char*)malloc(256); |
| | | name[0] = '\0'; |
| | | |
| | | while (*reader != 0) { |
| | | if (*reader >= 192) { |
| | | offset = (*reader)*256+ *(reader+1) - 49152; |
| | | reader = buffer+offset-1; |
| | | jumped=1; |
| | | } else { |
| | | name[p++]=*reader; |
| | | } |
| | | reader = reader+1; |
| | | if (jumped == 0) { |
| | | *count = *count+1; |
| | | } |
| | | } |
| | | name[p] = '\0'; |
| | | if (jumped == 1) { |
| | | *count = *count + 1; |
| | | } |
| | | while (*reader != 0) { |
| | | if (*reader >= 192) { |
| | | offset = (*reader) * 256 + *(reader + 1) - 49152; |
| | | reader = buffer + offset - 1; |
| | | jumped = 1; |
| | | } else { |
| | | name[p++] = *reader; |
| | | } |
| | | reader = reader + 1; |
| | | if (jumped == 0) { |
| | | *count = *count + 1; |
| | | } |
| | | } |
| | | name[p] = '\0'; |
| | | if (jumped == 1) { |
| | | *count = *count + 1; |
| | | } |
| | | |
| | | //convert from dns format to normal |
| | | for (i = 0; i < strlen((const char*)name); i++) { |
| | | p = name[i]; |
| | | for (j = 0; j < p; j++) { |
| | | name[i] = name[i+1]; |
| | | i++; |
| | | } |
| | | name[i] = '.'; |
| | | } |
| | | name[i-1] = '\0'; |
| | | return name; |
| | | // convert from dns format to normal |
| | | for (i = 0; i < strlen((const char*)name); i++) { |
| | | p = name[i]; |
| | | for (j = 0; j < p; j++) { |
| | | name[i] = name[i + 1]; |
| | | i++; |
| | | } |
| | | name[i] = '.'; |
| | | } |
| | | name[i - 1] = '\0'; |
| | | return name; |
| | | } |
| | |
| | | // DNS resource records |
| | | #define T_A 1 // IPv4 address |
| | | #define T_NS 2 // Name Server |
| | | #define T_CNAME 5 // Cannonical name |
| | | #define T_SOA 6 // State of Authority |
| | | #define T_PTR 12 // Domain name pointer |
| | | #define T_MX 15 // Mail exchange |
| | | #define T_TXT 16 // Text record |
| | | #define T_AAAA 28 // IPv6 address |
| | | #define T_A 1 // IPv4 address |
| | | #define T_NS 2 // Name Server |
| | | #define T_CNAME 5 // Cannonical name |
| | | #define T_SOA 6 // State of Authority |
| | | #define T_PTR 12 // Domain name pointer |
| | | #define T_MX 15 // Mail exchange |
| | | #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 |
| | | |
| | | int test_dns(void); |
| | | void *test_server(void *in); |
| | | void *print_progress(void *in); |
| | | void* test_server(void* in); |
| | | 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; |
| | | struct hosts_list* hosts = NULL; |
| | | struct dns_list* servers = NULL; |
| | | |
| | | int main(int argc, char** argv) |
| | | { |
| | | int option, added_hosts = 0; |
| | | while((option = getopt(argc, argv, "s:a:t:n:h")) != -1) { |
| | | while ((option = getopt(argc, argv, "s:a:t:n:h")) != -1) { |
| | | switch (option) { |
| | | case 's': //server to use |
| | | case 's': // server to use |
| | | add_dns_server(&servers, optarg); |
| | | num_servers++; |
| | | break; |
| | | case 'a': //hostname to search |
| | | case 'a': // hostname to search |
| | | add_hosts_server(&hosts, optarg); |
| | | added_hosts++; |
| | | break; |
| | | case 't': //set number of hosts to test |
| | | case 't': // set number of hosts to test |
| | | num_hosts = atoi(optarg); |
| | | break; |
| | | case 'n': //number of tests to perform |
| | | case 'n': // number of tests to perform |
| | | num_tests = atoi(optarg); |
| | | break; |
| | | case '?': |
| | |
| | | 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); |
| | | exit(1); |
| | | } |
| | | } |
| | | if (num_hosts == 0 || num_hosts > NUM_HOSTNAMES+added_hosts) { |
| | | if (num_hosts == 0 || num_hosts > NUM_HOSTNAMES + added_hosts) { |
| | | num_hosts = NUM_HOSTNAMES + added_hosts; |
| | | } |
| | | for (int i = added_hosts; i < num_hosts; i++) { |
| | | add_hosts_server(&hosts, (char*)HOSTNAMES[i-added_hosts]); |
| | | add_hosts_server(&hosts, (char*)HOSTNAMES[i - added_hosts]); |
| | | } |
| | | for (int i = 0; i < NUM_DNS; i++) { |
| | | add_dns_server(&servers, (char*)DNS_SERVERS[i]); |
| | |
| | | } |
| | | |
| | | // 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; |
| | | struct dns_list* curr = servers; |
| | | int i = 0; |
| | | pthread_t *threads = malloc(num_servers*sizeof(pthread_t)); |
| | | pthread_t* threads = malloc(num_servers * sizeof(pthread_t)); |
| | | pthread_t progress; |
| | | pthread_create(&progress, NULL, print_progress, NULL); |
| | | while (curr) { |
| | |
| | | } |
| | | |
| | | // Tests an individual dns server with all the hostnames configured |
| | | void *test_server(void *in) |
| | | void* test_server(void* in) |
| | | { |
| | | unsigned long long avg_nsec = 0; |
| | | struct dns_list *dns = (struct dns_list *)in; |
| | | dns->time.tv_sec = 0; dns->time.tv_nsec = 0; |
| | | struct dns_list* dns = (struct dns_list*)in; |
| | | dns->time.tv_sec = 0; |
| | | dns->time.tv_nsec = 0; |
| | | for (int i = 0; i < num_tests; i++) { |
| | | struct hosts_list *curr = hosts; |
| | | 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; |
| | | dns->time.tv_sec = dns->time.tv_sec/(num_hosts*num_tests); |
| | | dns->time.tv_nsec = avg_nsec/(num_hosts*num_tests); |
| | | 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 |
| | | void *print_progress(void *in) |
| | | // 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 |
| | | #define NUM_DNS 26 |
| | | |
| | | const char HOSTNAMES[NUM_HOSTNAMES][20] = { |
| | | "google.com", "youtube.com", |
| | | "tmail.com", "baidu.com", |
| | | "facebook.com", "qq.com", |
| | | "sohu.com", "taobao.com", |
| | | "360.cn", "jd.com", |
| | | "yahoo.com", "amazon.com", |
| | | "wikipedia.org", "zoom.us", |
| | | "weibo.com", "sina.com.cn", |
| | | "live.com", "reddit.com", |
| | | "netflix.com", "Xinhuanet.com", |
| | | "Microsoft.com", "Okezone.com", |
| | | "Office.com", "Vk.com", |
| | | "Instagram.com", "Alipay.com", |
| | | "Csdn.net", "Microsoftonline.com", |
| | | "Myshopify.com", "Yahoo.co.jp", |
| | | "Bongacams.com", "Twitch.tv", |
| | | "Panda.tv", "Zhanqi.tv", |
| | | "Google.com.hk", "Naver.com", |
| | | "Bing.com", "Amazon.in", |
| | | "ebay.com", "Apple.com", |
| | | "China.com.cn", "Tianya.cn", |
| | | "Aliexpress.com", "Amazon.co.jp", |
| | | "Google.co.in", "Stackoverflow.com", |
| | | "Livejasmin.com", "Adobe.com", |
| | | "Tribunnews.com", "Yandex.ru", |
| | | "google.com", "youtube.com", |
| | | "tmail.com", "baidu.com", |
| | | "facebook.com", "qq.com", |
| | | "sohu.com", "taobao.com", |
| | | "360.cn", "jd.com", |
| | | "yahoo.com", "amazon.com", |
| | | "wikipedia.org", "zoom.us", |
| | | "weibo.com", "sina.com.cn", |
| | | "live.com", "reddit.com", |
| | | "netflix.com", "Xinhuanet.com", |
| | | "Microsoft.com", "Okezone.com", |
| | | "Office.com", "Vk.com", |
| | | "Instagram.com", "Alipay.com", |
| | | "Csdn.net", "Microsoftonline.com", |
| | | "Myshopify.com", "Yahoo.co.jp", |
| | | "Bongacams.com", "Twitch.tv", |
| | | "Panda.tv", "Zhanqi.tv", |
| | | "Google.com.hk", "Naver.com", |
| | | "Bing.com", "Amazon.in", |
| | | "ebay.com", "Apple.com", |
| | | "China.com.cn", "Tianya.cn", |
| | | "Aliexpress.com", "Amazon.co.jp", |
| | | "Google.co.in", "Stackoverflow.com", |
| | | "Livejasmin.com", "Adobe.com", |
| | | "Tribunnews.com", "Yandex.ru", |
| | | }; |
| | | |
| | | const char DNS_SERVERS[NUM_DNS][20] = { |
| | | "1.1.1.1", "1.0.0.1", // Cloudflare |
| | | "8.8.8.8", "8.8.4.4", // Google |
| | | "9.9.9.9", "149.122.122.122", // Quad9 |
| | | "208.67.222.222", "208.67.220.220", // OpenDNS home |
| | | "185.228.168.9", "185.220.169.9", // CleanBrowsing |
| | | "64.6.64.6", "64.6.65.6", // Verisign |
| | | "198.101.242.72", "23.253.163.53", // Alternate DNS |
| | | "96.140.14.14", "94.140.15.15", // AdGuard DNS |
| | | "8.26.56.26", "8.20.247.20", // Comodo Secure DNS |
| | | "84.200.69.80", "84.200.70.40", // DNS Watch |
| | | "77.88.8.8", "77.88.88.1", // Yandex |
| | | "91.239.100.100", "89.233.43.71", // UnsensoredDNS |
| | | "156.154.70.1", "156.154.71.2", // Neustar |
| | | "1.1.1.1", "1.0.0.1", // Cloudflare |
| | | "8.8.8.8", "8.8.4.4", // Google |
| | | "9.9.9.9", "149.122.122.122", // Quad9 |
| | | "208.67.222.222", "208.67.220.220", // OpenDNS home |
| | | "185.228.168.9", "185.220.169.9", // CleanBrowsing |
| | | "64.6.64.6", "64.6.65.6", // Verisign |
| | | "198.101.242.72", "23.253.163.53", // Alternate DNS |
| | | "96.140.14.14", "94.140.15.15", // AdGuard DNS |
| | | "8.26.56.26", "8.20.247.20", // Comodo Secure DNS |
| | | "84.200.69.80", "84.200.70.40", // DNS Watch |
| | | "77.88.8.8", "77.88.88.1", // Yandex |
| | | "91.239.100.100", "89.233.43.71", // UnsensoredDNS |
| | | "156.154.70.1", "156.154.71.2", // Neustar |
| | | }; |
| | |
| | | #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); |
| | | 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); |
| | | int comp_times(struct timespec a, struct timespec b); |
| | | |
| | | int add_hosts_server(struct hosts_list **head, char *server) |
| | | int add_hosts_server(struct hosts_list** head, char* server) |
| | | { |
| | | struct hosts_list *end; |
| | | if (!(*head)) { |
| | | *head = malloc(sizeof(struct hosts_list)); |
| | | end = *head; |
| | | } else { |
| | | end = *head; |
| | | while (end->next) |
| | | end = end->next; |
| | | end->next = malloc(sizeof(struct hosts_list)); |
| | | end = end->next; |
| | | } |
| | | end->next = NULL; |
| | | end->server = server; |
| | | return 0; |
| | | struct hosts_list* end; |
| | | if (!(*head)) { |
| | | *head = malloc(sizeof(struct hosts_list)); |
| | | end = *head; |
| | | } else { |
| | | end = *head; |
| | | while (end->next) |
| | | end = end->next; |
| | | end->next = malloc(sizeof(struct hosts_list)); |
| | | end = end->next; |
| | | } |
| | | end->next = NULL; |
| | | end->server = server; |
| | | return 0; |
| | | } |
| | | |
| | | int free_hosts_list(struct hosts_list **head) |
| | | int free_hosts_list(struct hosts_list** head) |
| | | { |
| | | struct hosts_list *temp; |
| | | while (*head) { |
| | | temp = (*head)->next; |
| | | free(*head); |
| | | *head = temp; |
| | | } |
| | | return 0; |
| | | struct hosts_list* temp; |
| | | while (*head) { |
| | | temp = (*head)->next; |
| | | free(*head); |
| | | *head = temp; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | int add_dns_server(struct dns_list **head, char* server) |
| | | int add_dns_server(struct dns_list** head, char* server) |
| | | { |
| | | struct dns_list *end; |
| | | if (!(*head)) { |
| | | *head = malloc(sizeof(struct dns_list)); |
| | | end = *head; |
| | | } else { |
| | | end = *head; |
| | | while (end->next) |
| | | end = end->next; |
| | | end->next = malloc(sizeof(struct dns_list)); |
| | | end = end->next; |
| | | } |
| | | end->next = NULL; |
| | | end->server = server; |
| | | end->time.tv_nsec = 0; end->time.tv_sec = 0; |
| | | return 0; |
| | | struct dns_list* end; |
| | | if (!(*head)) { |
| | | *head = malloc(sizeof(struct dns_list)); |
| | | end = *head; |
| | | } else { |
| | | end = *head; |
| | | while (end->next) |
| | | end = end->next; |
| | | end->next = malloc(sizeof(struct dns_list)); |
| | | end = end->next; |
| | | } |
| | | end->next = NULL; |
| | | end->server = server; |
| | | end->time.tv_nsec = 0; |
| | | end->time.tv_sec = 0; |
| | | return 0; |
| | | } |
| | | |
| | | int free_dns_list(struct dns_list **head) |
| | | int free_dns_list(struct dns_list** head) |
| | | { |
| | | struct dns_list *temp; |
| | | while (*head) { |
| | | temp = (*head)->next; |
| | | free(*head); |
| | | *head = temp; |
| | | } |
| | | return 0; |
| | | struct dns_list* temp; |
| | | while (*head) { |
| | | temp = (*head)->next; |
| | | free(*head); |
| | | *head = temp; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | // Sort with merge sort as works well for linked lists |
| | | // Copied from https://www.geeksforgeeks.org/merge-sort-for-linked-list/ |
| | | int sort_servers(struct dns_list **headRef) |
| | | int sort_servers(struct dns_list** headRef) |
| | | { |
| | | struct dns_list *head = *headRef; |
| | | struct dns_list* head = *headRef; |
| | | struct dns_list *a, *b; |
| | | if (!head || !(head->next)) { //Empty list or containing one element |
| | | if (!head || !(head->next)) { // Empty list or containing one element |
| | | return 0; |
| | | } |
| | | split(head, &a, &b); |
| | |
| | | return 0; |
| | | } |
| | | |
| | | void split(struct dns_list *head, struct dns_list **a, struct dns_list **b) |
| | | void split(struct dns_list* head, struct dns_list** a, struct dns_list** b) |
| | | { |
| | | struct dns_list *fast = head->next, *slow = head; |
| | | while(fast) { |
| | | while (fast) { |
| | | fast = fast->next; |
| | | if (fast) { |
| | | slow = slow->next; |
| | |
| | | slow->next = NULL; |
| | | } |
| | | |
| | | struct dns_list *merge(struct dns_list *a, struct dns_list *b) |
| | | 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; |
| | | struct dns_list* out = NULL; |
| | | if (!a) return b; |
| | | if (!b) return a; |
| | | |
| | | if (comp_times(a->time, b->time) > 0) { |
| | | out = b; |
| | |
| | | return -1; |
| | | } |
| | | |
| | | int print_servers(struct dns_list *head) |
| | | int print_servers(struct dns_list* head) |
| | | { |
| | | 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; |
| | |
| | | #include "time.h" |
| | | |
| | | struct hosts_list { |
| | | char* server; |
| | | struct hosts_list* next; |
| | | char* server; |
| | | struct hosts_list* next; |
| | | }; |
| | | |
| | | struct dns_list { |
| | | char *server; |
| | | struct timespec time; |
| | | struct dns_list *next; |
| | | char* server; |
| | | struct timespec time; |
| | | struct dns_list* next; |
| | | }; |
| | | |
| | | int add_hosts_server(struct hosts_list **head, char *server); |
| | | int free_hosts_list(struct hosts_list **head); |
| | | int add_dns_server(struct dns_list **head, char *server); |
| | | int free_dns_list(struct dns_list **head); |
| | | int sort_servers(struct dns_list **headRef); |
| | | int print_servers(struct dns_list *head); |
| | | int add_hosts_server(struct hosts_list** head, char* server); |
| | | int free_hosts_list(struct hosts_list** head); |
| | | int add_dns_server(struct dns_list** head, char* server); |
| | | int free_dns_list(struct dns_list** head); |
| | | int sort_servers(struct dns_list** headRef); |
| | | int print_servers(struct dns_list* head); |