commit 3c0a63afbbd8509a597a584ec333426ae371a590
parent 81f6fe189ebf440b19b3a31b99c628a4813929dd
Author: Nibo <kroekerrobin@gmail.com>
Date: Mon, 14 Apr 2025 08:53:36 +0200
Rewrite everything
Diffstat:
| M | Makefile | | | 7 | +++++-- |
| M | dinoco.1 | | | 6 | +++--- |
| M | dinoco.c | | | 1657 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | dinoco.h | | | 161 | ++++++++++++++++++++++++++++++------------------------------------------------- |
4 files changed, 900 insertions(+), 931 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,8 +1,10 @@
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
-all:
- $(CC) -g -O -Wall -Werror -o dinoco dinoco.c
+dinoco:
+ $(CC) -O -Wall -Wextra -pedantic -o dinoco dinoco.c
+debug:
+ $(CC) -DDEBUG -g -Wall -Wextra -pedantic -o dinoco dinoco.c
clean:
rm dinoco
install: all
@@ -15,3 +17,4 @@ install: all
uninstall:
rm "$(PREFIX)/bin/dinoco"
rm "$(MANPREFIX)/man1/dinoco.1"
+.PHONY: debug clean install uninstall
diff --git a/dinoco.1 b/dinoco.1
@@ -31,15 +31,15 @@ Not supported types: WKS, MB, MD, MF, MG, MR, MINFO, NULL.
Disable the printing of the header line.
.SH EXAMPLES
.EX
-\fB\,$\/\fR dinoco -d blubiblub.org -t MX
+\fB\,$\/\fR dinoco -t MX blubiblub.org
Mail Exchange Preference
mail.blubiblub.org 10
\fB\,$\/\fR
-\fB\,$\/\fR dinoco -d blubiblub.org -t A
+\fB\,$\/\fR dinoco -t A blubiblub.org
Address
221.180.67.12
\fB\,$\/\fR
-\fB\,$\/\fR dinoco -d honkaponka.org -t MX -h
+\fB\,$\/\fR dinoco -h -t MX honkaponka.org
mail.honkaponla.org 10
alt1.mail.honkaponla.org 20
\fB\,$\/\fR
diff --git a/dinoco.c b/dinoco.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
+#include <unistd.h>
#include <getopt.h>
#include <ctype.h>
#include <sys/socket.h>
@@ -11,340 +12,400 @@
#include <inttypes.h>
#include "dinoco.h"
-inline char *stringCat(char *str1, char *str2)
+static struct DnsHeader dns_header_default = {
+ .id = 55,
+ .qr = false,
+ .opcode = OPCODE_QUERY,
+ .aa = false,
+ .tc = false,
+ .rd = true,
+ .ra = false,
+ .rcode = RCODE_NO_ERROR,
+ .qdcount = 1,
+ .ancount = 0,
+ .nscount = 0,
+ .arcount = 0
+};
+
+static void
+byte_array_free(struct ByteArray *bytes)
{
- int str1Len = strlen(str1);
- int str2Len = strlen(str2);
- char *string = malloc((str1Len+str2Len+1) * sizeof(char));
- int i = 0;
- int k = 0;
- for (; i<str1Len; i++)
- {
- string[i] = str1[i];
- }
- for (; k<str2Len; k++)
- {
- string[i+k] = str2[k];
- }
- string[i+k] = '\0';
- free(str1);
- free(str2);
- return string;
+ free(bytes->b);
+ free(bytes);
}
-char *getRCODEString(enum rcode code)
+static void
+resource_record_free(struct DnsResourceRecord *record)
{
- switch (code)
- {
- case RCODE_FORMAT_ERROR:
- return "Format Error";
- break;
- case RCODE_SERVER_FAILURE:
- return "Server Failure";
- break;
- case RCODE_NAME_ERROR:
- return "Name Error";
- break;
- case RCODE_NOT_IMPLEMENTED:
- return "Not Implemented";
- break;
- case RCODE_REFUSED:
- return "Refused";
- break;
- default:
- return "";
+ free(record->domain);
+ byte_array_free(record->rdata);
+ free(record);
+}
+
+static char *
+str_cat(const char *str1, const char *str2)
+{
+ char *new, *n;
+ const char *c;
+ new = malloc((strlen(str1)+strlen(str2)+1) * sizeof(char));
+ n = new;
+ for (c = str1; *c; c++, n++) {
+ *n = *c;
+ }
+ for (c = str2; *c; c++, n++) {
+ *n = *c;
+ }
+ *n = 0;
+ return new;
+}
+
+static char *
+str_to_upper(const char *str)
+{
+ char *new, *n;
+ const char *c;
+ new = malloc((strlen(str)+1) * sizeof(char));
+ for (c = str, n = new; *c; c++, n++) {
+ *n = toupper(*c);
+ }
+ *n = 0;
+ return new;
+}
+
+static const char *
+response_code_to_string(enum ResponseCode code)
+{
+ switch (code) {
+ case RCODE_NO_ERROR:
+ return "No error condition";
+ case RCODE_FORMAT_ERROR:
+ return "Format Error";
+ case RCODE_SERVER_FAILURE:
+ return "Server Failure";
+ case RCODE_NAME_ERROR:
+ return "Name Error";
+ case RCODE_NOT_IMPLEMENTED:
+ return "Not Implemented";
+ case RCODE_REFUSED:
+ return "Refused";
}
+ return "";
}
-char *getDNSServerIP()
+/* TODO: Find a better way to get a dns server ip. This is ugly. */
+static char *
+dns_server_ip_get(void)
{
+ FILE *fp;
+ char *ipv4;
+ size_t bytes_read;
const char *cmd = "cat /etc/resolv.conf | grep 'nameserver.*\\..*' | cut -d' ' -f2 | tr -d '\n'";
- FILE *fp = popen(cmd, "r");
- char *buf = malloc(16 * sizeof(char));
- size_t bytesRead = fread(buf, 1, 15, fp);
+ fp = popen(cmd, "r");
+ if (!fp) {
+ LOG_DEBUG("popen failed.");
+ return NULL;
+ }
+ ipv4 = malloc(16 * sizeof(char));
+ bytes_read = fread(ipv4, 1, 15, fp);
pclose(fp);
- if (bytesRead >= MIN_IP_LENGTH)
- {
- buf[bytesRead] = 0;
+ if (bytes_read >= MIN_IP_LENGTH) {
+ ipv4[bytes_read] = 0;
struct sockaddr_in sa;
- int ret = inet_pton(AF_INET, buf, &(sa.sin_addr));
- if (ret != 0)
- return buf;
- else
- return "";
+ if (inet_pton(AF_INET, ipv4, &sa.sin_addr) != 0) {
+ return ipv4;
+ }
}
- return "";
+ return NULL;
}
-char *toUpper(char *string)
+static struct ByteArray *
+dns_server_request(char *request, size_t request_len)
{
- char *newString = malloc((strlen(string)+1) * sizeof(char));
- int i = 0;
- for (; i<strlen(string); i++)
- {
- newString[i] = toupper(string[i]);
+ int port = 53;
+ int fd;
+ size_t bytes_sent, bytes_received;
+ socklen_t size;
+ struct ByteArray *res;
+ char *ip = dns_server_ip_get();
+ if (!ip) {
+ LOG_DEBUG("dns_server_ip_get failed.");
+ return NULL;
+ }
+ struct hostent *host = (struct hostent *)gethostbyname(ip);
+ free(ip);
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ perror("socket failed");
+ return NULL;
+ }
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr = *((struct in_addr *)host->h_addr);
+ memset(&addr.sin_zero, 0, 8);
+ size = (socklen_t)sizeof(addr);
+ bytes_sent = sendto(fd, request, request_len, 0, (struct sockaddr *)&addr, size);
+ if (bytes_sent == request_len) {
+ char response[MAX_UDP_MSG_LENGTH * sizeof(char)];
+ bytes_received = recvfrom(fd, response, MAX_UDP_MSG_LENGTH, 0, (struct sockaddr *)&addr, &size);
+ if (bytes_received > 0) {
+ res = malloc(sizeof(struct ByteArray));
+ res->b = malloc(bytes_received * sizeof(char));
+ memcpy(res->b, &response, bytes_received);
+ res->len = bytes_received;
+ return res;
+ } else {
+ fprintf(stderr, "Didn't receive a response.\n");
+ return NULL;
+ }
+ } else {
+ fprintf(stderr, "Didn't send whole request.\n");
+ return NULL;
}
- newString[i] = 0;
- free(string);
- return newString;
}
-short parseType(char *arg)
+static enum Type
+type_parse(const char *str, bool *error)
{
- for (int i=0; i<17; i++)
- {
- if (strcmp(arg, types[i].string) == 0)
- {
- free(arg);
- return types[i].type;
- }
- }
- free(arg);
- return -1;
+ *error = false;
+ if (!strcmp(str, "A")) {
+ return TYPE_A;
+ } else
+ if (!strcmp(str, "NS")) {
+ return TYPE_NS;
+ } else
+ if (!strcmp(str, "MD")) {
+ return TYPE_MD;
+ } else
+ if (!strcmp(str, "MF")) {
+ return TYPE_MF;
+ } else
+ if (!strcmp(str, "CNAME")) {
+ return TYPE_CNAME;
+ } else
+ if (!strcmp(str, "SOA")) {
+ return TYPE_SOA;
+ } else
+ if (!strcmp(str, "MB")) {
+ return TYPE_MB;
+ } else
+ if (!strcmp(str, "MG")) {
+ return TYPE_MG;
+ } else
+ if (!strcmp(str, "MR")) {
+ return TYPE_MR;
+ } else
+ if (!strcmp(str, "NULL")) {
+ return TYPE_NULL;
+ } else
+ if (!strcmp(str, "WKS")) {
+ return TYPE_WKS;
+ } else
+ if (!strcmp(str, "PTR")) {
+ return TYPE_PTR;
+ } else
+ if (!strcmp(str, "HINFO")) {
+ return TYPE_HINFO;
+ } else
+ if (!strcmp(str, "MINFO")) {
+ return TYPE_MINFO;
+ } else
+ if (!strcmp(str, "MX")) {
+ return TYPE_MX;
+ } else
+ if (!strcmp(str, "TXT")) {
+ return TYPE_TXT;
+ } else
+ if (!strcmp(str, "AAAA")) {
+ return TYPE_AAAA;
+ }
+ *error = true;
+ return TYPE_A; // unused
}
// e.g. "domain.com" -> 6, 'd', 'o', 'm', 'a', 'i', 'n', 3, 'c', 'o', 'm', 0
-struct byte_array *formDomain(char *domain)
+static struct ByteArray *
+domain_form(const char *str)
{
- char *dnsDomain = malloc(sizeof(char));
- int i = 0;
- int q = 0;
- int domainLabelCharCount = 0;
- char c;
- while ((c = domain[i]) != '\0')
- {
- if (c == '.')
- {
- dnsDomain = realloc(dnsDomain, (q + 1) * sizeof(char));
- dnsDomain[q] = domainLabelCharCount;
- q++;
- for (int k=i-domainLabelCharCount; k<i; k++)
- {
- dnsDomain = realloc(dnsDomain, (q + 1) * sizeof(char));
- dnsDomain[q] = domain[k];
- q++;
+ struct ByteArray *bytes;
+ char *domain = NULL;
+ int d = 0;
+ int k, i;
+ int char_count = 0;
+ for (i = 0; str[i]; i++) {
+ if (str[i] == '.') {
+ domain = realloc(domain, (d+char_count+1) * sizeof(char));
+ domain[d] = char_count;
+ d++;
+ for (k = i-char_count; k<i; k++, d++) {
+ domain[d] = str[k];
}
- domainLabelCharCount = 0;
+ char_count = 0;
+ } else {
+ char_count++;
}
- else
- {
- domainLabelCharCount++;
- }
- i++;
}
- dnsDomain = realloc(dnsDomain, (q + 1) * sizeof(char));
- dnsDomain[q] = domainLabelCharCount;
- q++;
- for (int k=i-domainLabelCharCount; k<i; k++)
- {
- dnsDomain = realloc(dnsDomain, (q + 1) * sizeof(char));
- dnsDomain[q] = domain[k];
- q++;
- }
- dnsDomain = realloc(dnsDomain, (q + 1) * sizeof(char));
- dnsDomain[q] = 0;
- dnsDomain = realloc(dnsDomain, (q + 1 + 4) * sizeof(char));
- struct byte_array *b = malloc(sizeof(struct byte_array));
- b->bytes = dnsDomain;
- b->length = q + 1;
- return b;
+ domain = realloc(domain, (d+char_count+2) * sizeof(char));
+ domain[d] = char_count;
+ d++;
+ for (k = i-char_count; k<i; k++, d++) {
+ domain[d] = str[k];
+ }
+ domain[d] = 0;
+ bytes = malloc(sizeof(struct ByteArray));
+ bytes->b = (uint8_t *)domain;
+ bytes->len = d + 1;
+ return bytes;
}
-char *parseIPv4(char *data)
+static char *
+domain_parse(const struct ByteArray *bytes, int start)
{
- char *ipv4 = NULL;
- int e = 0;
- uint8_t ipPart = 0;
- for (int i=0; i<4; i++)
- {
- ipPart = data[i] & 0xFF;
- char number[4];
- sprintf(number, "%d", ipPart);
- number[3] = 0;
- for (int k=0; k<strlen(number); k++)
- {
- ipv4 = realloc(ipv4, (e+1) * sizeof(char));
- ipv4[e] = number[k];
- e++;
- }
- if (i != 3)
- {
- ipv4 = realloc(ipv4, (e+1) * sizeof(char));
- ipv4[e] = '.';
- e++;
- }
- }
- ipv4 = realloc(ipv4, (e+1) * sizeof(char));
- ipv4[e] = 0;
- return ipv4;
+ char *merged_domain, *string;
+ char *domain = NULL;
+ int offset, len;
+ int d = 0;
+ int i = start;
+ do {
+ // if pointer
+ if (bytes->b[i] & 0b11000000) {
+ offset = bytes->b[i+1];
+ string = domain_parse(bytes, offset);
+ domain = realloc(domain, (d+1) * sizeof(char));
+ domain[d] = 0;
+ merged_domain = str_cat(domain, string);
+ free(domain);
+ free(string);
+ return merged_domain;
+ }
+ len = bytes->b[i];
+ domain = realloc(domain, (d+len) * sizeof(char));
+ memcpy(&domain[d], &bytes->b[i+1], len);
+ d += len;
+ i += len + 1;
+ if (bytes->b[i]) {
+ domain = realloc(domain, (d+1) * sizeof(char));
+ domain[d] = '.';
+ d++;
+ }
+ } while (bytes->b[i]);
+ domain = realloc(domain, (d+1) * sizeof(char));
+ domain[d] = 0;
+ return domain;
}
-char *parseIPv6(char *data)
+static char *
+ipv4_parse(const uint8_t data[4])
{
- char *ipv6 = NULL;
- char ipv6Part[3];
- int s = 0;
- for (int i=0; i<16; i++)
- {
- uint8_t n = data[i] & 0xFF;
- sprintf(ipv6Part, "%02x", n);
- ipv6Part[2] = 0;
- for (int k=0; k<strlen(ipv6Part); k++)
- {
- ipv6 = realloc(ipv6, (s+1) * sizeof(char));
- ipv6[s] = ipv6Part[k];
- s++;
- }
- if (i%2 != 0 && i != 15)
- {
- ipv6 = realloc(ipv6, (s+1) * sizeof(char));
- ipv6[s] = ':';
- s++;
- }
- }
- ipv6 = realloc(ipv6, (s+1) * sizeof(char));
- ipv6[s] = 0;
- return ipv6;
+ char *ipv4 = NULL;
+ char number[4];
+ uint8_t ip_part;
+ int i = 0;
+ int k, char_wrote;
+ for (k = 0; k<4; k++) {
+ ip_part = data[k] & 0xFF;
+ char_wrote = snprintf(number, 4, "%d", ip_part);
+ ipv4 = realloc(ipv4, (i+char_wrote+1) * sizeof(char));
+ strcpy(&ipv4[i], number);
+ i += char_wrote;
+ if (k != 3) {
+ ipv4 = realloc(ipv4, (i+1) * sizeof(char));
+ ipv4[i] = '.';
+ i++;
+ }
+ }
+ return ipv4;
}
-char *parseCharString(char *data, int start)
+static char *
+ipv6_parse(const uint8_t data[16])
{
- char *string = NULL;
+ char *ipv6 = malloc(40 * sizeof(char));
int i = 0;
- for (; i<data[start]; i++)
- {
- string = realloc(string, (i+1) * sizeof(char));
- string[i] = data[start+i+1];
+ char number[3];
+ uint8_t ip_part;
+ int k;
+ for (k = 0; k<16; k++) {
+ ip_part = data[k] & 0xFF;
+ snprintf(number, 3, "%02x", ip_part);
+ memcpy(&ipv6[i], number, 2);
+ i += 2;
+ if (k % 2 != 0 && k != 15) {
+ ipv6[i] = ':';
+ i++;
+ }
}
- string = realloc(string, (i+1) * sizeof(char));
- string[i] = 0;
- return string;
+ ipv6[i] = 0;
+ return ipv6;
}
-char *parseDomain(struct byte_array *res, int start)
+static char *
+char_string_parse(uint8_t *data, int start)
{
- char *domain = NULL;
- char *mergedDomain = NULL;
- char *string = NULL;
- int offset = 0;
- int k = 0;
- int i = start;
- while (res->bytes[i] != 0)
- {
- // If pointer
- if (res->bytes[i] & 0b11000000)
- {
- offset = res->bytes[i+1];
- string = parseDomain(res, offset);
- domain = realloc(domain, (k+1) * sizeof(char));
- domain[k] = 0;
- mergedDomain = stringCat(domain, string);
- return mergedDomain;
- }
- for (int s=0; s<res->bytes[i]; s++)
- {
- domain = realloc(domain, (k+1) * sizeof(char));
- domain[k] = res->bytes[i+s+1];
- k++;
- }
- i += res->bytes[i] + 1;
- if (res->bytes[i] != 0)
- {
- domain = realloc(domain, (k+1) * sizeof(char));
- domain[k] = '.';
- k++;
- }
- else
- {
- break;
- }
- }
- domain = realloc(domain, (k+1) * sizeof(char));
- domain[k] = 0;
- return domain;
+ int len = data[start];
+ char *str = malloc((len+1) * sizeof(char));
+ memcpy(str, &data[start+1], len);
+ str[len] = 0;
+ return str;
}
-struct byte_array *formHeader(struct dns_header *h)
+static struct ByteArray *
+header_form(struct DnsHeader *h)
{
- struct byte_array *header = malloc(sizeof(struct byte_array));
- header->bytes = malloc(DNS_HEADER_LENGTH * sizeof(char));
- header->length = DNS_HEADER_LENGTH;
- header->bytes[0] = (h->id >> 8) & 0xFF;
- header->bytes[1] = h->id & 0xFF;
- char flagOne = 0;
+ struct ByteArray *header = malloc(sizeof(struct ByteArray));
+ header->b = malloc(DNS_HEADER_LENGTH * sizeof(char));
+ header->len = DNS_HEADER_LENGTH;
+ header->b[0] = (h->id >> 8) & 0xFF;
+ header->b[1] = h->id & 0xFF;
+ char flag_one = 0;
if (h->qr)
- flagOne = flagOne | 0b10000000;
+ flag_one = flag_one | 0b10000000;
switch (h->opcode)
{
case OPCODE_QUERY:
// The bit we would set to zero is already zero
break;
case OPCODE_IQUERY:
- flagOne = flagOne | 0b10001000;
+ flag_one = flag_one | 0b10001000;
break;
case OPCODE_STATUS:
- flagOne = flagOne | 0b10010000;
+ flag_one = flag_one | 0b10010000;
break;
}
if (h->aa)
- flagOne = flagOne | 0b00000100;
+ flag_one = flag_one | 0b00000100;
if (h->tc)
- flagOne = flagOne | 0b00000010;
+ flag_one = flag_one | 0b00000010;
if (h->rd)
- flagOne = flagOne | 0b00000001;
- header->bytes[2] = flagOne;
- char flagTwo = 0;
+ flag_one = flag_one | 0b00000001;
+ header->b[2] = flag_one;
+ char flag_two = 0;
if (h->ra)
- flagTwo = flagTwo | 0b10000000;
- header->bytes[3] = flagTwo;
- header->bytes[4] = (h->qdcount >> 8) & 0xFF;
- header->bytes[5] = h->qdcount & 0xFF;
- header->bytes[6] = (h->ancount >> 8) & 0xFF;
- header->bytes[7] = h->ancount & 0xFF;
- header->bytes[8] = (h->nscount >> 8) & 0xFF;
- header->bytes[9] = h->nscount & 0xFF;
- header->bytes[10] = (h->arcount >> 8) & 0xFF;
- header->bytes[11] = h->arcount & 0xFF;
+ flag_two = flag_two | 0b10000000;
+ header->b[3] = flag_two;
+ header->b[4] = (h->qdcount >> 8) & 0xFF;
+ header->b[5] = h->qdcount & 0xFF;
+ header->b[6] = (h->ancount >> 8) & 0xFF;
+ header->b[7] = h->ancount & 0xFF;
+ header->b[8] = (h->nscount >> 8) & 0xFF;
+ header->b[9] = h->nscount & 0xFF;
+ header->b[10] = (h->arcount >> 8) & 0xFF;
+ header->b[11] = h->arcount & 0xFF;
return header;
}
-struct byte_array *formQuestion(struct dns_question *qu)
+static struct DnsHeader *
+header_parse(const uint8_t *res)
{
- struct byte_array *question = malloc(sizeof(struct byte_array));
- question->bytes = NULL;
- struct byte_array *d = formDomain(qu->domain);
- int i = 0;
- for (; i<d->length; i++)
- {
- question->bytes = realloc(question->bytes, (i+1) * sizeof(char));
- question->bytes[i] = d->bytes[i];
- }
- question->length = d->length;
- question->bytes = realloc(question->bytes, (i+4) * sizeof(char));
- question->bytes[i] = 0x00;
- question->bytes[i+1] = qu->type;
- question->bytes[i+2] = 0x00;
- question->bytes[i+3] = qu->class;
- question->length = d->length+4;
- free(d->bytes);
- free(d);
- return question;
-}
-
-struct dns_header *parseHeader(char *res)
-{
- struct dns_header *header = malloc(sizeof(struct dns_header));
+ struct DnsHeader *header = malloc(sizeof(struct DnsHeader));
header->id = res[1] + 256U*res[0];
header->qr = res[2] & 0b10000000 ? true : false;
- if (res[2] & 0b00001000)
- {
+ if (res[2] & 0b00001000) {
header->opcode = OPCODE_IQUERY;
- }
- else if (res[2] & 0b00010000)
- {
+ } else
+ if (res[2] & 0b00010000) {
header->opcode = OPCODE_STATUS;
- }
- else {
+ } else {
header->opcode = OPCODE_QUERY;
}
header->aa = res[2] & 0b00000100 ? true : false;
@@ -359,620 +420,566 @@ struct dns_header *parseHeader(char *res)
if (res[3] & 0b00000100)
rcode += 4;
header->rcode = rcode;
- header->qdcount = res[5] + 256U*res[4];
- header->ancount = res[7] + 256U*res[6];
- header->nscount = res[9] + 256U*res[8];
- header->arcount = res[11] + 256U*res[10];
+ header->qdcount = res[5] + 256U * res[4];
+ header->ancount = res[7] + 256U * res[6];
+ header->nscount = res[9] + 256U * res[8];
+ header->arcount = res[11] + 256U * res[10];
return header;
}
-int findNameLength(struct byte_array *res, int start)
+static struct ByteArray *
+question_form(struct DnsQuestion *qu)
{
- int length = 0;
- int i = start;
- while (1)
- {
- if (res->bytes[i] == 0)
- {
- length++;
+ struct ByteArray *question = malloc(sizeof(struct ByteArray));
+ struct ByteArray *domain = domain_form(qu->domain);
+ question->b = malloc((domain->len+4) * sizeof(char));
+ question->len = domain->len+4;
+ memcpy(question->b, domain->b, domain->len);
+ question->b[domain->len] = 0x00;
+ question->b[domain->len+1] = qu->type;
+ question->b[domain->len+2] = 0x00;
+ question->b[domain->len+3] = qu->class;
+ byte_array_free(domain);
+ return question;
+}
+
+static int
+name_count_bytes(struct ByteArray *bytes, int start)
+{
+ int count = 0;
+ int i;
+ for (i = start; true; i++, count++) {
+ if (bytes->b[i] == 0) {
+ count++;
break;
}
- // If pointer
- if ((res->bytes[i] & 0xFF) == 0xC0)
- {
- length += 2;
+ // if pointer
+ if ((bytes->b[i] & 0xFF) == 0xC0) {
+ count += 2;
break;
}
- length++;
- i++;
}
- return length;
+ return count;
}
-struct dns_resource_record *parseAnswer(struct byte_array *res, int *start)
+static struct DnsResourceRecord *
+answer_parse(struct ByteArray *res, int *start)
{
- struct dns_resource_record *answer = malloc(sizeof(struct dns_resource_record));
- answer->domain = parseDomain(res, *start);
- int nameLength = findNameLength(res, *start);
- int b = *start + nameLength;
- answer->type = res->bytes[b+1];
- answer->class = res->bytes[b+3];
- answer->ttl = res->bytes[b+7]
- + 256U*res->bytes[b+6]
- + 65536U*res->bytes[b+5]
- + 16777216U*res->bytes[b+4];
- answer->rdlength = res->bytes[b+9]
- + 256U*res->bytes[b+8];
- answer->rdata = malloc(sizeof(struct byte_array));
- answer->rdata->bytes = NULL;
- answer->rdata->length = answer->rdlength;
- int i = 0;
- for (; i<answer->rdlength; i++)
- {
- answer->rdata->bytes = realloc(answer->rdata->bytes, (i+1) * sizeof(char));
- answer->rdata->bytes[i] = res->bytes[b+10+i];
- }
- *start += nameLength + 10 + answer->rdlength;
+ struct DnsResourceRecord *answer = malloc(sizeof(struct DnsResourceRecord));
+ answer->domain = domain_parse(res, *start);
+ int name_len = name_count_bytes(res, *start);
+ int b = *start + name_len;
+ answer->type = res->b[b+1] & 0xFF;
+ answer->class = res->b[b+3] & 0xFF;
+ answer->ttl = (res->b[b+7] & 0xFF)
+ + 256U * (res->b[b+6] & 0xFF)
+ + 65536U * (res->b[b+5] & 0xFF)
+ + 16777216U * (res->b[b+4] & 0xFF);
+ answer->rdlength = (res->b[b+9] & 0xFF) + 256U * (res->b[b+8] & 0xFF);
+ answer->rdata = malloc(sizeof(struct ByteArray));
+ answer->rdata->b = malloc(answer->rdlength * sizeof(char));
+ answer->rdata->len = answer->rdlength;
+ memcpy(answer->rdata->b, &res->b[b+10], answer->rdlength);
+ *start += name_len + 10 + answer->rdlength;
return answer;
}
-union dns_type_result *parseAnswerByType
-(
- struct dns_resource_record *answer,
- enum type type,
- struct byte_array *res,
- int *startOfNextAnswer
+static union DnsTypeResult *
+answer_parse_by_type(
+ struct DnsResourceRecord *answer,
+ struct ByteArray *res,
+ enum Type type,
+ int *start_of_next_answer
)
{
- union dns_type_result *ur = malloc(sizeof(union dns_type_result));
- switch (type)
- {
- case TYPE_A:
- ur->a = malloc(sizeof(struct dns_a_result));
- ur->a->ipAddress = parseIPv4(answer->rdata->bytes);
- break;
- case TYPE_AAAA:
- ur->aaaa = malloc(sizeof(struct dns_aaaa_result));
- ur->aaaa->ipv6 = parseIPv6(answer->rdata->bytes);
- break;
- case TYPE_NS:
- ur->ns = malloc(sizeof(struct dns_ns_result));
- int startOfDomain = *startOfNextAnswer - answer->rdlength;
- ur->ns->domain = parseDomain(res, startOfDomain);
- break;
- case TYPE_MD:
- break;
- case TYPE_MF:
- break;
- case TYPE_CNAME:
- ur->cname = malloc(sizeof(struct dns_cname_result));
- int startOfCanonicalDomain = *startOfNextAnswer - answer->rdlength;
- ur->cname->domain = parseDomain(res, startOfCanonicalDomain);
- break;
- case TYPE_SOA:
- ur->soa = malloc(sizeof(struct dns_soa_result));
- int start = *startOfNextAnswer - answer->rdlength;
- ur->soa->mname = parseDomain(res, start);
- int mnameLength = findNameLength(res, start);
- start += mnameLength;
- ur->soa->rname = parseDomain(res, start);
- int rnameLength = findNameLength(res, start);
- start += rnameLength;
- ur->soa->serial = ((uint32_t)(res->bytes[start] & 0xFF) << 24)
- + ((uint32_t)(res->bytes[start+1] & 0xFF) << 16)
- + ((uint32_t)(res->bytes[start+2] & 0xFF) << 8)
- + (uint32_t)(res->bytes[start+3] & 0xFF);
- start += 4;
- ur->soa->refresh = ((uint32_t)(res->bytes[start] & 0xFF) << 24)
- + ((uint32_t)(res->bytes[start+1] & 0xFF) << 16)
- + ((uint32_t)(res->bytes[start+2] & 0xFF) << 8)
- + (uint32_t)(res->bytes[start+3] & 0xFF);
- start += 4;
- ur->soa->retry = ((uint32_t)(res->bytes[start] & 0xFF) << 24)
- + ((uint32_t)(res->bytes[start+1] & 0xFF) << 16)
- + ((uint32_t)(res->bytes[start+2] & 0xFF) << 8)
- + (uint32_t)(res->bytes[start+3] & 0xFF);
- start += 4;
- ur->soa->expire = ((uint32_t)(res->bytes[start] & 0xFF) << 24)
- + ((uint32_t)(res->bytes[start+1] & 0xFF) << 16)
- + ((uint32_t)(res->bytes[start+2] & 0xFF) << 8)
- + (uint32_t)(res->bytes[start+3] & 0xFF);
- start += 4;
- ur->soa->minimum = ((uint32_t)(res->bytes[start] & 0xFF) << 24)
- + ((uint32_t)(res->bytes[start+1] & 0xFF) << 16)
- + ((uint32_t)(res->bytes[start+2] & 0xFF) << 8)
- + (uint32_t)(res->bytes[start+3] & 0xFF);
- break;
- case TYPE_MB:
- break;
- case TYPE_MG:
- break;
- case TYPE_MR:
- break;
- case TYPE_NULL:
- break;
- case TYPE_WKS:
- break;
- case TYPE_PTR:
- ur->ptr = malloc(sizeof(struct dns_ptr_result));
- int startOfPTRDomain = *startOfNextAnswer - answer->rdlength;
- ur->ptr->domain = parseDomain(res, startOfPTRDomain);
- break;
- case TYPE_HINFO:
- ur->hinfo = malloc(sizeof(struct dns_hinfo_result));
- ur->hinfo->cpu = parseCharString(answer->rdata->bytes, 0);
- int startOfOS = answer->rdata->bytes[0] + 1;
- ur->hinfo->os = parseCharString(answer->rdata->bytes, startOfOS);
- break;
- case TYPE_MINFO:
- break;
- case TYPE_MX:
- uint16_t preference = answer->rdata->bytes[1]
- + 256U*answer->rdata->bytes[0];
- int startOfMailDomain = *startOfNextAnswer - answer->rdlength + 2;
- ur->mx = malloc(sizeof(struct dns_mx_result));
- ur->mx->preference = preference;
- ur->mx->mailDomain = parseDomain(res, startOfMailDomain);
- break;
- case TYPE_TXT:
- ur->txt = malloc(sizeof(struct dns_txt_result));
- ur->txt->data = NULL;
- int txtLength = answer->rdata->bytes[0];
- int i = 0;
- for (; i<txtLength; i++)
- {
- ur->txt->data = realloc(ur->txt->data, (i+1) * sizeof(char));
- ur->txt->data[i] = answer->rdata->bytes[i+1];
- }
- ur->txt->data = realloc(ur->txt->data, (i+1) * sizeof(char));
- ur->txt->data[i] = 0;
- break;
+ union DnsTypeResult *ur = malloc(sizeof(union DnsTypeResult));
+ switch (type) {
+ case TYPE_A:
+ ur->a = malloc(sizeof(struct DnsAResult));
+ ur->a->ipv4 = ipv4_parse(answer->rdata->b);
+ break;
+ case TYPE_AAAA:
+ ur->aaaa = malloc(sizeof(struct DnsAaaaResult));
+ ur->aaaa->ipv6 = ipv6_parse(answer->rdata->b);
+ break;
+ case TYPE_NS:
+ ur->ns = malloc(sizeof(struct DnsNsResult));
+ int start_of_domain = *start_of_next_answer - answer->rdlength;
+ ur->ns->domain = domain_parse(res, start_of_domain);
+ break;
+ case TYPE_MD:
+ break;
+ case TYPE_MF:
+ break;
+ case TYPE_CNAME:
+ ur->cname = malloc(sizeof(struct DnsCnameResult));
+ int start_of_canonical_domain = *start_of_next_answer - answer->rdlength;
+ ur->cname->domain = domain_parse(res, start_of_canonical_domain);
+ break;
+ case TYPE_SOA:
+ ur->soa = malloc(sizeof(struct DnsSoaResult));
+ int start = *start_of_next_answer - answer->rdlength;
+ ur->soa->mname = domain_parse(res, start);
+ int mname_len = name_count_bytes(res, start);
+ start += mname_len;
+ ur->soa->rname = domain_parse(res, start);
+ int rname_len = name_count_bytes(res, start);
+ start += rname_len;
+ ur->soa->serial = ((uint32_t)(res->b[start] & 0xFF) << 24)
+ + ((uint32_t)(res->b[start+1] & 0xFF) << 16)
+ + ((uint32_t)(res->b[start+2] & 0xFF) << 8)
+ + (uint32_t)(res->b[start+3] & 0xFF);
+ start += 4;
+ ur->soa->refresh = ((uint32_t)(res->b[start] & 0xFF) << 24)
+ + ((uint32_t)(res->b[start+1] & 0xFF) << 16)
+ + ((uint32_t)(res->b[start+2] & 0xFF) << 8)
+ + (uint32_t)(res->b[start+3] & 0xFF);
+ start += 4;
+ ur->soa->retry = ((uint32_t)(res->b[start] & 0xFF) << 24)
+ + ((uint32_t)(res->b[start+1] & 0xFF) << 16)
+ + ((uint32_t)(res->b[start+2] & 0xFF) << 8)
+ + (uint32_t)(res->b[start+3] & 0xFF);
+ start += 4;
+ ur->soa->expire = ((uint32_t)(res->b[start] & 0xFF) << 24)
+ + ((uint32_t)(res->b[start+1] & 0xFF) << 16)
+ + ((uint32_t)(res->b[start+2] & 0xFF) << 8)
+ + (uint32_t)(res->b[start+3] & 0xFF);
+ start += 4;
+ ur->soa->minimum = ((uint32_t)(res->b[start] & 0xFF) << 24)
+ + ((uint32_t)(res->b[start+1] & 0xFF) << 16)
+ + ((uint32_t)(res->b[start+2] & 0xFF) << 8)
+ + (uint32_t)(res->b[start+3] & 0xFF);
+ break;
+ case TYPE_MB:
+ break;
+ case TYPE_MG:
+ break;
+ case TYPE_MR:
+ break;
+ case TYPE_NULL:
+ break;
+ case TYPE_WKS:
+ break;
+ case TYPE_PTR:
+ ur->ptr = malloc(sizeof(struct DnsPtrResult));
+ int start_of_ptr_domain = *start_of_next_answer - answer->rdlength;
+ ur->ptr->domain = domain_parse(res, start_of_ptr_domain);
+ break;
+ case TYPE_HINFO:
+ ur->hinfo = malloc(sizeof(struct DnsHinfoResult));
+ ur->hinfo->cpu = char_string_parse(answer->rdata->b, 0);
+ int start_of_os = answer->rdata->b[0] + 1;
+ ur->hinfo->os = char_string_parse(answer->rdata->b, start_of_os);
+ break;
+ case TYPE_MINFO:
+ break;
+ case TYPE_MX: {
+ uint16_t preference = answer->rdata->b[1]
+ + 256U * answer->rdata->b[0];
+ int start_of_mail_domain = *start_of_next_answer - answer->rdlength + 2;
+ ur->mx = malloc(sizeof(struct DnsMxResult));
+ ur->mx->preference = preference;
+ ur->mx->mail_domain = domain_parse(res, start_of_mail_domain);
+ break;
+ }
+ case TYPE_TXT: {
+ int txt_len;
+ int txt_data_len = 0;
+ int b = 0;
+ ur->txt = malloc(sizeof(struct DnsTxtResult));
+ ur->txt->data = NULL;
+ do {
+ txt_len = answer->rdata->b[b] & 0xFF;
+ txt_data_len += txt_len;
+ ur->txt->data = realloc(ur->txt->data, txt_data_len * sizeof(char));
+ memcpy(&ur->txt->data[txt_data_len-txt_len], &answer->rdata->b[b+1], txt_len);
+ b += txt_len + 1;
+ } while (txt_len > 0);
+ ur->txt->data = realloc(ur->txt->data, (txt_data_len+1) * sizeof(char));
+ ur->txt->data[txt_data_len] = 0;
+ break;
+ }
}
- free(answer->rdata->bytes);
- free(answer->rdata);
- free(answer->domain);
- free(answer);
return ur;
}
-void printAnswers
-(
- union dns_type_result **answers,
- int answerCount,
- enum type type,
- struct byte_array *res,
- int *startOfNextAnswer,
- bool disableHeader
+static void
+answers_print(
+ union DnsTypeResult **answers,
+ int answer_count,
+ enum Type type,
+ bool disable_header
)
{
+ int i;
int len = 0;
- switch (type)
- {
- case TYPE_A:
- if (!disableHeader)
- printf(ANSI_COLOR_GREEN"Address\n"ANSI_COLOR_RESET);
- for (int i=0; i<answerCount; i++)
- {
- printf("%s\n", answers[i]->a->ipAddress);
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->a->ipAddress);
- free(answers[i]->a);
- free(answers[i]);
- }
- break;
- case TYPE_AAAA:
- if (!disableHeader)
- {
- printf(ANSI_COLOR_GREEN);
- printf("AAAA Address\n");
- printf(ANSI_COLOR_RESET);
- }
- for (int i=0; i<answerCount; i++)
- {
- printf("%s\n", answers[i]->aaaa->ipv6);
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->aaaa->ipv6);
- free(answers[i]->aaaa);
- free(answers[i]);
- }
- break;
- case TYPE_NS:
- if (!disableHeader)
- printf(ANSI_COLOR_GREEN"Authoritative Host\n"ANSI_COLOR_RESET);
- for (int i=0; i<answerCount; i++)
- {
- printf("%s\n", answers[i]->ns->domain);
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->ns->domain);
- free(answers[i]->ns);
- free(answers[i]);
- }
- break;
- case TYPE_MD:
- break;
- case TYPE_MF:
- break;
- case TYPE_CNAME:
- if (!disableHeader)
- printf(ANSI_COLOR_GREEN"Canonical Domain\n"ANSI_COLOR_RESET);
- for (int i=0; i<answerCount; i++)
- {
- printf("%s\n", answers[i]->cname->domain);
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->cname->domain);
- free(answers[i]->cname);
- free(answers[i]);
- }
- break;
- case TYPE_SOA:
- int longestMName = 0;
- for (int i=0; i<answerCount; i++)
- {
- if ((len = strlen(answers[i]->soa->mname)) > longestMName)
- longestMName = len;
- }
- len = 0;
- if (longestMName < 19)
- longestMName = 19;
- int longestRName = 0;
- for (int i=0; i<answerCount; i++)
- {
- if ((len = strlen(answers[i]->soa->rname)) > longestRName)
- longestRName = len;
- }
- if (longestRName < 31)
- longestRName = 31;
- if (!disableHeader)
- {
- printf(ANSI_COLOR_GREEN);
- printf("%-*s\t", longestMName, "Primary Name Server");
- printf("%-*s\t", longestRName, "Responsible authority's mailbox");
- printf("%-13s\t", "Serial Number");
- printf("%-16s\t", "Refresh Interval");
- printf("%-14s\t", "Retry Interval");
- printf("%-12s\t", "Expire Limit");
- printf("%-11s", "Minimum TTL");
- printf("\n");
- printf(ANSI_COLOR_RESET);
- }
- for (int i=0; i<answerCount; i++)
- {
- printf("%-*s\t", longestMName, answers[i]->soa->mname);
- printf("%-*s\t", longestRName, answers[i]->soa->rname);
- printf("%-13u\t", answers[i]->soa->serial);
- printf("%-16u\t", answers[i]->soa->refresh);
- printf("%-14u\t", answers[i]->soa->retry);
- printf("%-12u\t", answers[i]->soa->expire);
- printf("%-11u", answers[i]->soa->minimum);
- printf("\n");
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->soa->mname);
- free(answers[i]->soa->rname);
- free(answers[i]->soa);
- free(answers[i]);
- }
- break;
- case TYPE_MB:
- break;
- case TYPE_MG:
- break;
- case TYPE_MR:
- break;
- case TYPE_NULL:
- break;
- case TYPE_WKS:
- break;
- case TYPE_PTR:
- if (!disableHeader)
- {
- printf(ANSI_COLOR_GREEN);
- printf("Domain Name\n");
- printf(ANSI_COLOR_RESET);
- }
- for (int i=0; i<answerCount; i++)
- {
- printf("%s\n", answers[i]->ptr->domain);
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->ptr->domain);
- free(answers[i]->ptr);
- free(answers[i]);
- }
- break;
- case TYPE_HINFO:
- int longestCPU = 0;
- len = 0;
- for (int i=0; i<answerCount; i++)
- {
- if ((len = strlen(answers[i]->hinfo->cpu)) > longestCPU)
- longestCPU = len;
- }
- if (longestCPU < 3)
- longestCPU = 3;
- if (!disableHeader)
- {
- printf(ANSI_COLOR_GREEN);
- printf("CPU\t");
- printf("OS\n");
- printf(ANSI_COLOR_RESET);
- }
- for (int i=0; i<answerCount; i++)
- {
- printf("%-*s\t", longestCPU, answers[i]->hinfo->cpu);
- printf("%-*s", longestCPU, answers[i]->hinfo->os);
- printf("\n");
- }
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->hinfo->cpu);
- free(answers[i]->hinfo->os);
- free(answers[i]->hinfo);
- free(answers[i]);
- }
- break;
- case TYPE_MINFO:
- break;
- case TYPE_MX:
- int longestMailDomain = 0;
- size_t len = 0;
- for (int i=0; i<answerCount; i++)
- {
- if ((len = strlen(answers[i]->mx->mailDomain)) > longestMailDomain)
- longestMailDomain = len;
- }
- if (!disableHeader)
- printf(ANSI_COLOR_GREEN"%-*s\t%s\n"ANSI_COLOR_RESET, longestMailDomain, "Mail Exchange", "Preference");
- for (int i=0; i<answerCount; i++)
- {
- printf("%-*s\t", longestMailDomain, answers[i]->mx->mailDomain);
- printf("%d", answers[i]->mx->preference);
- printf("\n");
+ switch (type) {
+ case TYPE_A:
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"Address\n"ANSI_COLOR_RESET);
+ }
+ for (i = 0; i < answer_count; i++) {
+ printf("%s\n", answers[i]->a->ipv4);
+ }
+ break;
+ case TYPE_AAAA:
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"AAAA Address\n"ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%s\n", answers[i]->aaaa->ipv6);
+ }
+ break;
+ case TYPE_NS:
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"Authoritative Host\n"ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%s\n", answers[i]->ns->domain);
+ }
+ break;
+ case TYPE_MD:
+ break;
+ case TYPE_MF:
+ break;
+ case TYPE_CNAME:
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"Canonical Domain\n"ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%s\n", answers[i]->cname->domain);
+ }
+ break;
+ case TYPE_SOA: {
+ const char *mname_header = "Primary Name Server";
+ const char *rname_header = "Responsible authority's mailbox";
+ int mname_header_len = strlen(mname_header);
+ int rname_header_len = strlen(rname_header);
+ int longest_mname = 0;
+ int longest_rname = 0;
+ for (i = 0; i<answer_count; i++) {
+ len = strlen(answers[i]->soa->mname);
+ if (len > longest_mname) {
+ longest_mname = len;
}
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->mx->mailDomain);
- free(answers[i]->mx);
- free(answers[i]);
+ len = strlen(answers[i]->soa->rname);
+ if (len > longest_rname) {
+ longest_rname = len;
}
- break;
- case TYPE_TXT:
- if (!disableHeader)
- printf(ANSI_COLOR_GREEN"TXT Data\n"ANSI_COLOR_RESET);
- for (int i=0; i<answerCount; i++)
- {
- printf("%s\n", answers[i]->txt->data);
+ }
+ if (longest_mname < mname_header_len) {
+ longest_mname = mname_header_len;
+ }
+ if (longest_rname < rname_header_len) {
+ longest_rname = rname_header_len;
+ }
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN);
+ printf("%-*s\t", longest_mname, "Primary Name Server");
+ printf("%-*s\t", longest_rname, "Responsible authority's mailbox");
+ printf("%-13s\t", "Serial Number");
+ printf("%-16s\t", "Refresh Interval");
+ printf("%-14s\t", "Retry Interval");
+ printf("%-12s\t", "Expire Limit");
+ printf("%-11s\n", "Minimum TTL");
+ printf(ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%-*s\t", longest_mname, answers[i]->soa->mname);
+ printf("%-*s\t", longest_rname, answers[i]->soa->rname);
+ printf("%-13u\t", answers[i]->soa->serial);
+ printf("%-16u\t", answers[i]->soa->refresh);
+ printf("%-14u\t", answers[i]->soa->retry);
+ printf("%-12u\t", answers[i]->soa->expire);
+ printf("%-11u\n", answers[i]->soa->minimum);
+ }
+ break;
+ }
+ case TYPE_MB:
+ break;
+ case TYPE_MG:
+ break;
+ case TYPE_MR:
+ break;
+ case TYPE_NULL:
+ break;
+ case TYPE_WKS:
+ break;
+ case TYPE_PTR:
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"Domain Name\n"ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%s\n", answers[i]->ptr->domain);
+ }
+ break;
+ case TYPE_HINFO: {
+ const char *cpu_header = "CPU";
+ int cpu_header_len = strlen(cpu_header);
+ int longest_cpu = 0;
+ for (i = 0; i<answer_count; i++) {
+ len = strlen(answers[i]->hinfo->cpu);
+ if (len > longest_cpu) {
+ longest_cpu = len;
}
- for (int i=0; i<answerCount; i++)
- {
- free(answers[i]->txt->data);
- free(answers[i]->txt);
- free(answers[i]);
+ }
+ if (longest_cpu < cpu_header_len) {
+ longest_cpu = cpu_header_len;
+ }
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN);
+ printf("CPU\t");
+ printf("OS\n");
+ printf(ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%-*s\t", longest_cpu, answers[i]->hinfo->cpu);
+ printf("%-*s\n", longest_cpu, answers[i]->hinfo->os);
+ }
+ break;
+ }
+ case TYPE_MINFO:
+ break;
+ case TYPE_MX: {
+ int longest_mail_domain = 0;
+ for (i = 0; i<answer_count; i++) {
+ len = strlen(answers[i]->mx->mail_domain);
+ if (len > longest_mail_domain) {
+ longest_mail_domain = len;
}
- break;
+ }
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"%-*s\t%s\n"ANSI_COLOR_RESET, longest_mail_domain, "Mail Exchange", "Preference");
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%-*s\t", longest_mail_domain, answers[i]->mx->mail_domain);
+ printf("%d\n", answers[i]->mx->preference);
+ }
+ break;
+ }
+ case TYPE_TXT:
+ if (!disable_header) {
+ printf(ANSI_COLOR_GREEN"TXT Data\n"ANSI_COLOR_RESET);
+ }
+ for (i = 0; i<answer_count; i++) {
+ printf("%s\n", answers[i]->txt->data);
+ }
+ break;
}
- free(answers);
}
-struct byte_array *reqServer(char *req, int length)
+static void
+answers_free(
+ union DnsTypeResult **answers,
+ int answer_count,
+ enum Type type
+)
{
- char *ip = getDNSServerIP();
- if (strlen(ip) == 0)
- {
- fprintf(stderr, "getDNSServerIP failed.\n");
- return NULL;
- }
- struct hostent *host = (struct hostent *) gethostbyname(ip);
- free(ip);
- int port = 53;
- int fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd == -1)
- {
- perror("socket failed.\n");
- return NULL;
- }
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr = *((struct in_addr *)host->h_addr);
- bzero(&(addr.sin_zero), 8);
- socklen_t size = (socklen_t) sizeof(addr);
- size_t bytesSent = sendto(fd, req, length, 0, (struct sockaddr *) &addr, size);
- if (bytesSent == length)
- {
- char *res = malloc(MAX_UDP_MSG_LENGTH * sizeof(char));
- size_t bytesReceived = recvfrom(fd, res, MAX_UDP_MSG_LENGTH, 0, (struct sockaddr *) &addr, &size);
- if (bytesReceived > 0)
- {
- struct byte_array *response = malloc(sizeof(struct byte_array));
- response->bytes = NULL;
- for (int i=0; i<bytesReceived; i++)
- {
- response->bytes = realloc(response->bytes, (i+1) * sizeof(char));
- response->bytes[i] = res[i];
- }
- response->length = bytesReceived;
- free(res);
- return response;
+ int i;
+ switch (type) {
+ case TYPE_A:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->a->ipv4);
+ free(answers[i]->a);
+ free(answers[i]);
}
- else
- {
- free(res);
- fprintf(stderr, "Didn't receive a response.\n");
- return NULL;
+ break;
+ case TYPE_AAAA:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->aaaa->ipv6);
+ free(answers[i]->aaaa);
+ free(answers[i]);
}
+ break;
+ case TYPE_NS:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->ns->domain);
+ free(answers[i]->ns);
+ free(answers[i]);
+ }
+ break;
+ case TYPE_MD:
+ break;
+ case TYPE_MF:
+ break;
+ case TYPE_CNAME:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->cname->domain);
+ free(answers[i]->cname);
+ free(answers[i]);
+ }
+ break;
+ case TYPE_SOA:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->soa->mname);
+ free(answers[i]->soa->rname);
+ free(answers[i]->soa);
+ free(answers[i]);
+ }
+ break;
+ case TYPE_MB:
+ break;
+ case TYPE_MG:
+ break;
+ case TYPE_MR:
+ break;
+ case TYPE_NULL:
+ break;
+ case TYPE_WKS:
+ break;
+ case TYPE_PTR:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->ptr->domain);
+ free(answers[i]->ptr);
+ free(answers[i]);
+ }
+ break;
+ case TYPE_HINFO:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->hinfo->cpu);
+ free(answers[i]->hinfo->os);
+ free(answers[i]->hinfo);
+ free(answers[i]);
+ }
+ break;
+ case TYPE_MINFO:
+ break;
+ case TYPE_MX:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->mx->mail_domain);
+ free(answers[i]->mx);
+ free(answers[i]);
+ }
+ break;
+ case TYPE_TXT:
+ for (i = 0; i<answer_count; i++) {
+ free(answers[i]->txt->data);
+ free(answers[i]->txt);
+ free(answers[i]);
+ }
+ break;
}
- else
- {
- fprintf(stderr, "Didn't send whole request.\n");
- return NULL;
- }
+ free(answers);
}
-bool isValidResponse(struct dns_header *reqHeader, struct dns_header *resHeader)
+static bool
+response_is_valid(struct DnsHeader *req_header, struct DnsHeader *res_header)
{
- if (reqHeader->id != resHeader->id)
+ if (req_header->id != res_header->id) {
return false;
- if (resHeader->rcode != RCODE_NO_ERROR)
- {
- fprintf(stderr, "%s\n", getRCODEString(resHeader->rcode));
+ }
+ if (res_header->rcode != RCODE_NO_ERROR) {
+ fprintf(stderr, "Response code: %s\n", response_code_to_string(res_header->rcode));
return false;
}
- if (resHeader->ancount < reqHeader->qdcount)
+ if (res_header->ancount < req_header->qdcount) {
+ fprintf(stderr, "The server didn't provide an answer.\n");
return false;
+ }
return true;
}
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
{
static struct option options[] = {
{ "type", required_argument, 0, 't' },
{ "header", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
- int optionIndex = 0;
+ int option_index = 0;
int o = 0;
- char *domain;
- char *type = NULL;
- bool isType = false;
- bool disableHeader = false;
- while ((o = getopt_long(argc, argv, "t:h", options, &optionIndex)) != -1)
- {
- switch (o)
- {
- case 't':
- type = malloc((strlen(optarg)+1) * sizeof(char));
- strcpy(type, optarg);
- isType = true;
- break;
- case 'h':
- disableHeader = true;
- break;
- }
- }
- if (argc == optind)
- {
+ char *domain, *upper_type;
+ char type[5+1];
+ type[0] = 0;
+ bool disable_header = false;
+ bool error;
+ enum Type dns_type;
+ while ((o = getopt_long(argc, argv, "t:h", options, &option_index)) != -1) {
+ switch (o) {
+ case 't':
+ if (strlen(optarg) > 5) {
+ fprintf(stderr, "The provided type is too long.\n");
+ return 1;
+ }
+ strcpy(type, optarg);
+ break;
+ case 'h':
+ disable_header = true;
+ break;
+ }
+ }
+ if (argc == optind) {
fprintf(stderr, "Provide a domain!\n");
- free(type);
- return -1;
+ return 1;
}
- if (argc > optind+1)
- {
+ if (argc > optind+1) {
fprintf(stderr, "Provide only one domain!\n");
- free(type);
- return -1;
- }
- domain = malloc((strlen(argv[optind])+1) * sizeof(char));
- strcpy(domain, argv[optind]);
- if (!isType)
- {
- fprintf(stderr, "Provide a type (-t/--type)!\n");
- free(domain);
- return -1;
- }
- short tp = parseType(toUpper(type));
- if (tp == -1)
- {
- printf("You provided an invalid type.\n");
- free(domain);
- return -1;
- }
- enum type t = tp;
- struct byte_array *reqHeader = formHeader(&DNS_HEADER_DEFAULT);
- char *req = malloc(reqHeader->length * sizeof(char));
- int i = 0;
- for (; i<reqHeader->length; i++)
- {
- req[i] = reqHeader->bytes[i];
- }
- struct dns_question qu = {
+ return 1;
+ }
+ if (strlen(argv[optind]) > MAX_DOMAIN_LENGTH) {
+ fprintf(stderr, "The provided domain is too long.\n");
+ return 1;
+ }
+ domain = argv[optind];
+ if (type[0] == 0) {
+ fprintf(stderr, "Provide a type (-t/--type)!\n");
+ return 1;
+ }
+ upper_type = str_to_upper(type);
+ dns_type = type_parse(upper_type, &error);
+ if (error) {
+ fprintf(stderr, "You provided an invalid type.\n");
+ return 1;
+ }
+ free(upper_type);
+ struct ByteArray *header, *question, *res;
+ struct DnsHeader *res_header;
+ header = header_form(&dns_header_default);
+ struct DnsQuestion qu = {
.domain = domain,
- .type = t,
+ .type = dns_type,
.class = CLASS_IN
};
- struct byte_array *question = formQuestion(&qu);
- free(qu.domain);
- req = realloc(req, (reqHeader->length + question->length) * sizeof(char));
- for (int e=0; e<question->length; e++)
- {
- req[i] = question->bytes[e];
- i++;
- }
- int length = reqHeader->length + question->length;
- free(reqHeader->bytes);
- free(reqHeader);
- struct byte_array *res = reqServer(req, length);
- free(req);
- if (res == NULL)
- {
- fprintf(stderr, "reqServer failed.\n");
- return -1;
- }
- if (res->length >= DNS_HEADER_LENGTH)
- {
- /* printf("res:\n");
- for (int i=0; i<res->length; i++)
- {
- printf("%d: %02X\n", i, res->bytes[i]);
- }
- printf("\n"); */
- struct dns_header *resHeader = parseHeader(res->bytes);
- if (isValidResponse(&DNS_HEADER_DEFAULT, resHeader))
- {
- int answerCount = resHeader->ancount;
- int *startOfAnswer = malloc(sizeof(int));
- *startOfAnswer = DNS_HEADER_LENGTH + question->length;
- free(question->bytes);
- free(question);
- free(resHeader);
- /*
- This doesn't mean it's long enough to parse an answer
- but there is at least part of an answer.
- */
- if (res->length > *startOfAnswer)
- {
- struct dns_resource_record *answer;
- union dns_type_result **answers = NULL;
- for (int i=0; i<answerCount; i++)
- {
- answer = parseAnswer(res, startOfAnswer);
- union dns_type_result *r = parseAnswerByType(answer, t, res, startOfAnswer);
- answers = realloc(answers, (i+1) * sizeof(union dns_type_result));
- answers[i] = r;
- }
- printAnswers(answers, answerCount, t, res, startOfAnswer, disableHeader);
- }
- free(startOfAnswer);
- free(res->bytes);
- free(res);
- }
- else
- {
- free(res->bytes);
- free(res);
- free(resHeader);
- free(question->bytes);
- free(question);
- fprintf(stderr, "isValidResponse failed.\n");
- return -1;
- }
- }
- else
- {
- free(res->bytes);
- free(res);
- fprintf(stderr, "Response too short.\n");
- return -1;
- }
+ question = question_form(&qu);
+ char req[header->len + question->len];
+ memcpy(req, header->b, header->len);
+ memcpy(&req[header->len], question->b, question->len);
+ res = dns_server_request((char *)&req, header->len + question->len);
+ if (!res) {
+ LOG_DEBUG("dns_server_request failed.");
+ return 1;
+ }
+ byte_array_free(header);
+ if (res->len <= DNS_HEADER_LENGTH) {
+ fprintf(stderr, "Response is too short.\n");
+ return 1;
+ }
+ res_header = header_parse(res->b);
+ if (!response_is_valid(&dns_header_default, res_header)) {
+ fprintf(stderr, "Response isn't valid.\n");
+ return 1;
+ }
+ int answer_count = res_header->ancount;
+ free(res_header);
+ int *start_of_answer = malloc(sizeof(int));
+ *start_of_answer = DNS_HEADER_LENGTH + question->len;
+ byte_array_free(question);
+ if (res->len < *start_of_answer) {
+ fprintf(stderr, "Response doesn't include an answer.\n");
+ return 1;
+ }
+ struct DnsResourceRecord *answer;
+ union DnsTypeResult **answers = malloc(answer_count * sizeof(union DnsTypeResult *));
+ int i;
+ for (i = 0; i<answer_count; i++) {
+ answer = answer_parse(res, start_of_answer);
+ answers[i] = answer_parse_by_type(answer, res, dns_type, start_of_answer);
+ resource_record_free(answer);
+ }
+ answers_print(answers, answer_count, dns_type, disable_header);
+ answers_free(answers, answer_count, dns_type);
+ free(start_of_answer);
+ byte_array_free(res);
return 0;
}
diff --git a/dinoco.h b/dinoco.h
@@ -1,17 +1,28 @@
+#include <stdint.h>
+
+#define MAX_DOMAIN_LENGTH 253
#define MAX_UDP_MSG_LENGTH 512
#define DNS_HEADER_LENGTH 12
#define MIN_IP_LENGTH 7
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_RESET "\x1b[0m"
-struct byte_array
-{
- char *bytes;
- int length;
+#ifdef DEBUG
+#define LOG_DEBUG(msg) fprintf(stderr, msg"\n");
+#else
+#define LOG_DEBUG(msg)
+#endif
+
+enum ResponseCode {
+ RCODE_NO_ERROR,
+ RCODE_FORMAT_ERROR,
+ RCODE_SERVER_FAILURE,
+ RCODE_NAME_ERROR,
+ RCODE_NOT_IMPLEMENTED,
+ RCODE_REFUSED
};
-enum type
-{
+enum Type {
TYPE_A = 1,
TYPE_NS,
TYPE_MD,
@@ -31,133 +42,81 @@ enum type
TYPE_AAAA = 28
};
-struct typeMapping
-{
- char *string;
- enum type type;
-};
-
-const struct typeMapping types[] = {
- { "A", TYPE_A },
- { "NS", TYPE_NS },
- { "MD", TYPE_MD },
- { "MF", TYPE_MF },
- { "CNAME", TYPE_CNAME },
- { "SOA", TYPE_SOA },
- { "MB", TYPE_MB },
- { "MG", TYPE_MG },
- { "MR", TYPE_MR },
- { "NULL", TYPE_NULL },
- { "WKS", TYPE_WKS },
- { "PTR", TYPE_PTR },
- { "HINFO", TYPE_HINFO },
- { "MINFO", TYPE_MINFO },
- { "MX", TYPE_MX },
- { "TXT", TYPE_TXT },
- { "AAAA", TYPE_AAAA }
-};
-
-enum class
-{
+enum Class {
CLASS_IN = 1,
CLASS_CS,
CLASS_CH,
CLASS_HS
};
-enum opcode
-{
+enum OperationCode {
OPCODE_QUERY,
OPCODE_IQUERY,
OPCODE_STATUS
};
-enum rcode
-{
- RCODE_NO_ERROR,
- RCODE_FORMAT_ERROR,
- RCODE_SERVER_FAILURE,
- RCODE_NAME_ERROR,
- RCODE_NOT_IMPLEMENTED,
- RCODE_REFUSED
+struct ByteArray {
+ uint8_t *b;
+ size_t len;
};
-struct dns_header
-{
- uint16_t id; // char ID[2];
+struct DnsHeader {
+ uint16_t id;
bool qr;
- enum opcode opcode;
+ enum OperationCode opcode;
bool aa;
bool tc;
bool rd;
bool ra;
- enum rcode rcode;
- uint16_t qdcount; // char QDCOUNT[2];
- uint16_t ancount; // char ANCOUNT[2];
- uint16_t nscount; // char NSCOUNT[2];
- uint16_t arcount; // char ARCOUNT[2];
-};
-
-struct dns_header DNS_HEADER_DEFAULT = {
- .id = 55,
- .qr = false,
- .opcode = OPCODE_QUERY,
- .aa = false,
- .tc = false,
- .rd = true,
- .ra = false,
- .rcode = RCODE_NO_ERROR,
- .qdcount = 1,
- .ancount = 0,
- .nscount = 0,
- .arcount = 0
-};
-
-struct dns_question
-{
+ enum ResponseCode rcode;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+};
+
+struct DnsQuestion {
char *domain;
- enum type type;
- enum class class;
+ enum Type type;
+ enum Class class;
};
// Either Answer, Authority or Additional
-struct dns_resource_record
-{
+struct DnsResourceRecord {
char *domain;
- enum type type;
- enum class class;
+ enum Type type;
+ enum Class class;
int32_t ttl;
uint16_t rdlength;
- struct byte_array *rdata;
+ struct ByteArray *rdata;
};
-struct dns_mx_result
-{
+struct DnsMxResult {
uint16_t preference;
- char *mailDomain;
+ char *mail_domain;
};
-struct dns_a_result
+struct DnsAResult
{
- char *ipAddress;
+ char *ipv4;
};
-struct dns_ns_result
+struct DnsNsResult
{
char *domain;
};
-struct dns_cname_result
+struct DnsCnameResult
{
char *domain;
};
-struct dns_txt_result
+struct DnsTxtResult
{
char *data;
};
-struct dns_soa_result
+struct DnsSoaResult
{
char *mname;
char *rname;
@@ -168,31 +127,31 @@ struct dns_soa_result
uint32_t minimum;
};
-struct dns_ptr_result
+struct DnsPtrResult
{
char *domain;
};
-struct dns_hinfo_result
+struct DnsHinfoResult
{
char *cpu;
char *os;
};
-struct dns_aaaa_result
+struct DnsAaaaResult
{
char *ipv6;
};
-union dns_type_result
+union DnsTypeResult
{
- struct dns_mx_result *mx;
- struct dns_a_result *a;
- struct dns_ns_result *ns;
- struct dns_cname_result *cname;
- struct dns_txt_result *txt;
- struct dns_soa_result *soa;
- struct dns_ptr_result *ptr;
- struct dns_hinfo_result *hinfo;
- struct dns_aaaa_result *aaaa;
+ struct DnsMxResult *mx;
+ struct DnsAResult *a;
+ struct DnsNsResult *ns;
+ struct DnsCnameResult *cname;
+ struct DnsTxtResult *txt;
+ struct DnsSoaResult *soa;
+ struct DnsPtrResult *ptr;
+ struct DnsHinfoResult *hinfo;
+ struct DnsAaaaResult *aaaa;
};