summaryrefslogtreecommitdiff
path: root/src/packet/record.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/packet/record.c')
-rw-r--r--src/packet/record.c540
1 files changed, 540 insertions, 0 deletions
diff --git a/src/packet/record.c b/src/packet/record.c
new file mode 100644
index 0000000..29c3bf0
--- /dev/null
+++ b/src/packet/record.c
@@ -0,0 +1,540 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "record.h"
+#include "buffer.h"
+#include "../io/log.h"
+
+uint16_t record_to_id(RecordType type) {
+ switch (type) {
+ case A:
+ return 1;
+ case NS:
+ return 2;
+ case CNAME:
+ return 5;
+ case SOA:
+ return 6;
+ case PTR:
+ return 12;
+ case MX:
+ return 15;
+ case TXT:
+ return 16;
+ case AAAA:
+ return 28;
+ case SRV:
+ return 33;
+ case CAA:
+ return 257;
+ default:
+ return 0;
+ }
+}
+
+void record_from_id(uint16_t i, RecordType* type) {
+ switch (i) {
+ case 1:
+ *type = A;
+ break;
+ case 2:
+ *type = NS;
+ break;
+ case 5:
+ *type = CNAME;
+ break;
+ case 6:
+ *type = SOA;
+ break;
+ case 12:
+ *type = PTR;
+ break;
+ case 15:
+ *type = MX;
+ break;
+ case 16:
+ *type = TXT;
+ break;
+ case 28:
+ *type = AAAA;
+ break;
+ case 33:
+ *type = SRV;
+ break;
+ case 257:
+ *type = CAA;
+ break;
+ default:
+ *type = UNKOWN;
+ }
+}
+
+static void read_a_record(PacketBuffer* buffer, Record* record) {
+ ARecord data;
+ data.addr[0] = buffer_read(buffer);
+ data.addr[1] = buffer_read(buffer);
+ data.addr[2] = buffer_read(buffer);
+ data.addr[3] = buffer_read(buffer);
+
+ record->data.a = data;
+}
+
+static void read_ns_record(PacketBuffer* buffer, Record* record) {
+ NSRecord data;
+ buffer_read_qname(buffer, &data.host);
+
+ record->data.ns = data;
+}
+
+static void read_cname_record(PacketBuffer* buffer, Record* record) {
+ CNAMERecord data;
+ buffer_read_qname(buffer, &data.host);
+
+ record->data.cname = data;
+}
+
+static void read_soa_record(PacketBuffer* buffer, Record* record) {
+ SOARecord data;
+ buffer_read_qname(buffer, &data.mname);
+ buffer_read_qname(buffer, &data.nname);
+ data.serial = buffer_read_int(buffer);
+ data.refresh = buffer_read_int(buffer);
+ data.retry = buffer_read_int(buffer);
+ data.expire = buffer_read_int(buffer);
+ data.minimum = buffer_read_int(buffer);
+
+ record->data.soa = data;
+}
+
+static void read_ptr_record(PacketBuffer* buffer, Record* record) {
+ PTRRecord data;
+ buffer_read_qname(buffer, &data.pointer);
+
+ record->data.ptr = data;
+}
+
+static void read_mx_record(PacketBuffer* buffer, Record* record) {
+ MXRecord data;
+ data.priority = buffer_read_short(buffer);
+ buffer_read_qname(buffer, &data.host);
+
+ record->data.mx = data;
+}
+
+static void read_txt_record(PacketBuffer* buffer, Record* record) {
+ TXTRecord data;
+ data.len = 0;
+ data.text = malloc(sizeof(uint8_t*) * 2);
+
+ uint8_t capacity = 2;
+ while (1) {
+ if (data.len >= capacity) {
+ capacity *= 2;
+ data.text = realloc(data.text, sizeof(uint8_t*) * capacity);
+ }
+
+ buffer_read_string(buffer, &data.text[data.len]);
+ if(data.text[data.len][0] == 0) break;
+ data.len++;
+ }
+
+ record->data.txt = data;
+}
+
+static void read_aaaa_record(PacketBuffer* buffer, Record* record) {
+ AAAARecord data;
+ for (int i = 0; i < 16; i++) {
+ data.addr[i] = buffer_read(buffer);
+ }
+
+ record->data.aaaa = data;
+}
+
+static void read_srv_record(PacketBuffer* buffer, Record* record) {
+ SRVRecord data;
+ data.priority = buffer_read_short(buffer);
+ data.weight = buffer_read_short(buffer);
+ data.port = buffer_read_short(buffer);
+ buffer_read_qname(buffer, &data.target);
+
+ record->data.srv = data;
+}
+
+static void read_caa_record(PacketBuffer* buffer, Record* record, int header_pos) {
+ CAARecord data;
+ data.flags = buffer_read(buffer);
+ data.length = buffer_read(buffer);
+ buffer_read_n(buffer, &data.tag, data.length);
+ int value_len = ((int)record->len) + header_pos - buffer_get_index(buffer);
+ buffer_read_n(buffer, &data.value, (uint8_t)value_len);
+
+ record->data.caa = data;
+}
+
+void read_record(PacketBuffer* buffer, Record* record) {
+ buffer_read_qname(buffer, &record->domain);
+
+ uint16_t qtype_num = buffer_read_short(buffer);
+ record_from_id(qtype_num, &record->type);
+
+ record->cls = buffer_read_short(buffer);
+ record->ttl = buffer_read_int(buffer);
+ record->len = buffer_read_short(buffer);
+
+ int header_pos = buffer_get_index(buffer);
+
+ switch (record->type) {
+ case A:
+ read_a_record(buffer, record);
+ break;
+ case NS:
+ read_ns_record(buffer, record);
+ break;
+ case CNAME:
+ read_cname_record(buffer, record);
+ break;
+ case SOA:
+ read_soa_record(buffer, record);
+ break;
+ case PTR:
+ read_ptr_record(buffer, record);
+ break;
+ case MX:
+ read_mx_record(buffer, record);
+ break;
+ case TXT:
+ read_txt_record(buffer, record);
+ break;
+ case AAAA:
+ read_aaaa_record(buffer, record);
+ break;
+ case SRV:
+ read_srv_record(buffer, record);
+ break;
+ case CAA:
+ read_caa_record(buffer, record, header_pos);
+ break;
+ default:
+ buffer_step(buffer, record->len);
+ return;
+ }
+
+ INIT_LOG_BUFFER(log)
+ LOGONLY(print_record(record, log);)
+ TRACE("Reading record: %s", log);
+}
+
+static void write_a_record(PacketBuffer* buffer, Record* record) {
+ ARecord data = record->data.a;
+ buffer_write_short(buffer, 4);
+ buffer_write(buffer, record->data.a.addr[0]);
+ buffer_write(buffer, data.addr[1]);
+ buffer_write(buffer, data.addr[2]);
+ buffer_write(buffer, data.addr[3]);
+}
+
+static void write_ns_record(PacketBuffer* buffer, Record* record) {
+ NSRecord data = record->data.ns;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ buffer_write_qname(buffer, data.host);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_cname_record(PacketBuffer* buffer, Record* record) {
+ CNAMERecord data = record->data.cname;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ buffer_write_qname(buffer, data.host);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_soa_record(PacketBuffer* buffer, Record* record) {
+ SOARecord data = record->data.soa;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ buffer_write_qname(buffer, data.mname);
+ buffer_write_qname(buffer, data.nname);
+ buffer_write_int(buffer, data.serial);
+ buffer_write_int(buffer, data.refresh);
+ buffer_write_int(buffer, data.retry);
+ buffer_write_int(buffer, data.expire);
+ buffer_write_int(buffer, data.minimum);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_ptr_record(PacketBuffer* buffer, Record* record) {
+ PTRRecord data = record->data.ptr;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ buffer_write_qname(buffer, data.pointer);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_mx_record(PacketBuffer* buffer, Record* record) {
+ MXRecord data = record->data.mx;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ buffer_write_short(buffer, data.priority);
+ buffer_write_qname(buffer, data.host);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_txt_record(PacketBuffer* buffer, Record* record) {
+ TXTRecord data = record->data.txt;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ if(data.len == 0) {
+ return;
+ }
+
+ for(uint8_t i = 0; i < data.len; i++) {
+ buffer_write_string(buffer, data.text[i]);
+ }
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_aaaa_record(PacketBuffer* buffer, Record* record) {
+ AAAARecord data = record->data.aaaa;
+
+ buffer_write_short(buffer, 16);
+
+ for (int i = 0; i < 16; i++) {
+ buffer_write(buffer, data.addr[i]);
+ }
+}
+
+static void write_srv_record(PacketBuffer* buffer, Record* record) {
+ SRVRecord data = record->data.srv;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+
+ buffer_write_short(buffer, data.priority);
+ buffer_write_short(buffer, data.weight);
+ buffer_write_short(buffer, data.port);
+ buffer_write_qname(buffer, data.target);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_caa_record(PacketBuffer* buffer, Record* record) {
+ CAARecord data = record->data.caa;
+ int pos = buffer_get_index(buffer);
+ buffer_write_short(buffer, 0);
+ buffer_write(buffer, data.flags);
+ buffer_write(buffer, data.length);
+ buffer_write_n(buffer, data.tag + 1, data.tag[0]);
+ buffer_write_n(buffer, data.value + 1, data.value[0]);
+
+ int size = buffer_get_index(buffer) - pos - 2;
+ buffer_set_uint16_t(buffer, (uint16_t)size, pos);
+}
+
+static void write_record_header(PacketBuffer* buffer, Record* record) {
+ buffer_write_qname(buffer, record->domain);
+ uint16_t id = record_to_id(record->type);
+ buffer_write_short(buffer, id);
+ buffer_write_short(buffer, record->cls);
+ buffer_write_int(buffer, record->ttl);
+}
+
+void write_record(PacketBuffer* buffer, Record* record) {
+ switch(record->type) {
+ case A:
+ write_record_header(buffer, record);
+ write_a_record(buffer, record);
+ break;
+ case NS:
+ write_record_header(buffer, record);
+ write_ns_record(buffer, record);
+ break;
+ case CNAME:
+ write_record_header(buffer, record);
+ write_cname_record(buffer, record);
+ break;
+ case SOA:
+ write_record_header(buffer, record);
+ write_soa_record(buffer, record);
+ break;
+ case PTR:
+ write_record_header(buffer, record);
+ write_ptr_record(buffer, record);
+ break;
+ case MX:
+ write_record_header(buffer, record);
+ write_mx_record(buffer, record);
+ break;
+ case TXT:
+ write_record_header(buffer, record);
+ write_txt_record(buffer, record);
+ break;
+ case AAAA:
+ write_record_header(buffer, record);
+ write_aaaa_record(buffer, record);
+ break;
+ case SRV:
+ write_record_header(buffer, record);
+ write_srv_record(buffer, record);
+ break;
+ case CAA:
+ write_record_header(buffer, record);
+ write_caa_record(buffer, record);
+ break;
+ default:
+ break;
+ }
+
+ INIT_LOG_BUFFER(log)
+ LOGONLY(print_record(record, log);)
+ TRACE("Writing record: %s", log);
+}
+
+void free_record(Record* record) {
+ free(record->domain);
+ switch (record->type) {
+ case NS:
+ free(record->data.ns.host);
+ break;
+ case CNAME:
+ free(record->data.cname.host);
+ break;
+ case SOA:
+ free(record->data.soa.mname);
+ free(record->data.soa.nname);
+ break;
+ case PTR:
+ free(record->data.ptr.pointer);
+ break;
+ case MX:
+ free(record->data.mx.host);
+ break;
+ case TXT:
+ for (uint8_t i = 0; i < record->data.txt.len; i++) {
+ free(record->data.txt.text[i]);
+ }
+ free(record->data.txt.text);
+ break;
+ case SRV:
+ free(record->data.srv.target);
+ break;
+ case CAA:
+ free(record->data.caa.value);
+ free(record->data.caa.tag);
+ break;
+ default:
+ break;
+ }
+}
+
+void print_record(Record* record, char* buffer) {
+ INIT_LOG_BOUNDS
+ switch(record->type) {
+ case UNKOWN:
+ APPEND(buffer, "UNKOWN");
+ break;
+ case A:
+ APPEND(buffer, "A (%hhu.%hhu.%hhu.%hhu)",
+ record->data.a.addr[0],
+ record->data.a.addr[1],
+ record->data.a.addr[2],
+ record->data.a.addr[3]
+ );
+ break;
+ case NS:
+ APPEND(buffer, "NS (%.*s)",
+ record->data.ns.host[0],
+ record->data.ns.host + 1
+ );
+ break;
+ case CNAME:
+ APPEND(buffer, "CNAME (%.*s)",
+ record->data.cname.host[0],
+ record->data.cname.host + 1
+ );
+ break;
+ case SOA:
+ APPEND(buffer, "SOA (%.*s %.*s %u %u %u %u %u)",
+ record->data.soa.mname[0],
+ record->data.soa.mname + 1,
+ record->data.soa.nname[0],
+ record->data.soa.nname + 1,
+ record->data.soa.serial,
+ record->data.soa.refresh,
+ record->data.soa.retry,
+ record->data.soa.expire,
+ record->data.soa.minimum
+ );
+ break;
+ case PTR:
+ APPEND(buffer, "PTR (%.*s)",
+ record->data.ptr.pointer[0],
+ record->data.ptr.pointer + 1
+ );
+ break;
+ case MX:
+ APPEND(buffer, "MX (%.*s %hu)",
+ record->data.mx.host[0],
+ record->data.mx.host + 1,
+ record->data.mx.priority
+ );
+ break;
+ case TXT:
+ APPEND(buffer, "TXT (");
+ for(uint8_t i = 0; i < record->data.txt.len; i++) {
+ APPEND(buffer, "\"%.*s\"",
+ record->data.txt.text[i][0],
+ record->data.txt.text[i] + 1
+ );
+ }
+ APPEND(buffer, ")");
+ break;
+ case AAAA:
+ APPEND(buffer, "AAAA (");
+ for(int i = 0; i < 8; i++) {
+ APPEND(buffer, "%02hhx%02hhx:",
+ record->data.a.addr[i*2 + 0],
+ record->data.a.addr[i*2 + 1]
+ );
+ }
+ APPEND(buffer, ":)");
+ break;
+ case SRV:
+ APPEND(buffer, "SRV (%hu %hu %hu %.*s)",
+ record->data.srv.priority,
+ record->data.srv.weight,
+ record->data.srv.port,
+ record->data.srv.target[0],
+ record->data.srv.target + 1
+ );
+ break;
+ case CAA:
+ APPEND(buffer, "CAA (%hhu %.*s %.*s)",
+ record->data.caa.flags,
+ record->data.caa.tag[0],
+ record->data.caa.tag + 1,
+ record->data.caa.value[0],
+ record->data.caa.value + 1
+ );
+ break;
+ }
+} \ No newline at end of file