aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jonas Gunz <himself@jonasgunz.de> 2021-09-21 00:25:05 +0200
committerGravatar Jonas Gunz <himself@jonasgunz.de> 2021-09-21 00:25:05 +0200
commit35c378db771ea870c4a94ffc2331b13b3522cb3c (patch)
treee22612df400fa46c3f9e18b04dba07d311ad6fc9
parent859843ceda93c96bf0ab20ecf5b5e5a20456ea76 (diff)
downloaddns-35c378db771ea870c4a94ffc2331b13b3522cb3c.tar.gz
add record parser
-rw-r--r--src/record.c193
-rw-r--r--src/record.h19
-rw-r--r--src/zonefile.c46
-rw-r--r--src/zonefile.h1
4 files changed, 254 insertions, 5 deletions
diff --git a/src/record.c b/src/record.c
new file mode 100644
index 0000000..7ba40a3
--- /dev/null
+++ b/src/record.c
@@ -0,0 +1,193 @@
+/*
+ * src/record.c
+ * (c) 2021 Jonas Gunz <himself@jonasgunz.de>
+ * License: MIT
+ */
+
+/* https://datatracker.ietf.org/doc/html/rfc1035#section-3.3 */
+
+#include "record.h"
+
+/*
+ * Prototypes for rdata from string functions
+ * Arguments:
+ * _str: String representing rdata
+ * _rdata: A buffer containing the raw rdata will be alloced here
+ * Return: Length of alloced _rdata buffer, <0 on error
+ */
+
+/* Obsolete record types. Will throw error. */
+static ssize_t record_rdata_obsolete(char* _str, void** _rdata);
+
+/* Unimplemented record types. Will throw error. */
+static ssize_t record_rdata_not_implemented(char* _str, void** _rdata);
+
+/* rdata that does not need conversion from string form */
+static ssize_t record_rdata_verbatim(char* _str, void** _rdata);
+
+/* IPv4 Addresses */
+static ssize_t record_rdata_a(char* _str, void** _rdata);
+
+/* Start of authority */
+static ssize_t record_rdata_soa(char* _str, void** _rdata);
+
+static const char* const record_types[] = {
+ "A",
+ "NS",
+ "MD",
+ "MF",
+ "CNAME",
+ "SOA",
+ "MB",
+ "MG",
+ "MR",
+ "NULL",
+ "WKS",
+ "PTR",
+ "HINFO",
+ "MINFO",
+ "MX",
+ "TXT"
+};
+static const uint16_t record_types_len = sizeof(record_types) / sizeof(char*);
+
+static ssize_t (*record_rdata_creator[])(char*, void**) = {
+ &record_rdata_a, /* A */
+ &record_rdata_verbatim, /* NS */
+ &record_rdata_obsolete, /* MD */
+ &record_rdata_obsolete, /* MF */
+ &record_rdata_verbatim, /* CNAME */
+ &record_rdata_soa, /* SOA */
+
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+ &record_rdata_not_implemented,
+};
+
+static const char* const record_classes[] = {
+ "IN",
+ "CS",
+ "CH",
+ "HS"
+};
+static const uint16_t record_classes_len = sizeof(record_classes) / sizeof(char*);
+
+/* Implementation of RDATA cobverters */
+
+static ssize_t record_rdata_obsolete(char* _str, void** _rdata) {
+ LOGPRINTF(_LOG_ERROR, "Record type not obsolete");
+ return -1;
+}
+
+static ssize_t record_rdata_not_implemented(char* _str, void** _rdata) {
+ LOGPRINTF(_LOG_ERROR, "Record type not implemented");
+ return -1;
+}
+
+static ssize_t record_rdata_verbatim(char* _str, void** _rdata) {
+ size_t len;
+
+ if ( !_str || !_rdata )
+ return -1;
+
+ len = strlen(_str) + 1; /* Including \0 */
+
+ *_rdata = malloc(len);
+
+ if ( !*_rdata )
+ return -1;
+
+ strncpy(*_rdata, _str, len);
+
+ return (signed) len;
+}
+
+static ssize_t record_rdata_a(char* _str, void** _rdata) {
+ char* tok;
+ char* str;
+ char* end;
+ size_t len;
+ int i;
+
+ if ( !_str || !_rdata )
+ return -1;
+
+ len = strlen(_str) + 1;
+ str = malloc(len);
+ strncpy(str, _str, len);
+
+ *_rdata = malloc(4);
+ if ( !*_rdata )
+ return -1;
+
+ tok = strtok(str, ".");
+ if( !tok )
+ goto err;
+
+ ((uint8_t*)(*_rdata))[3] = (uint8_t) strtol(tok, &end, 10);
+
+ if( *end != '\0' )
+ goto err;
+
+ for( i=2; i>=0; i-- ) {
+ tok = strtok(NULL, ".");
+
+ if( !tok )
+ goto err;
+
+ ((uint8_t*)(*_rdata))[i] = (uint8_t) strtol(tok, &end, 10);
+
+ if( *end != '\0' )
+ goto err;
+ }
+
+ free(str);
+ return 4;
+err:
+ free(str);
+ return -1;
+}
+
+static ssize_t record_rdata_soa(char* _str, void** _rdata) {
+ LOGPRINTF(_LOG_ERROR, "Record type not implemented");
+ return -1;
+}
+
+
+/* Other methods */
+
+static uint16_t record_match_from_array(char* _str, const char* const _arr[], uint16_t _len) {
+ uint16_t i;
+
+ for( i=0; i<_len; i++ ){
+ if ( strcasecmp( _str, _arr[i] ) == 0 )
+ return i+1; /* Indices start with 1 */
+ }
+
+ return 0;
+}
+
+uint16_t record_class_from_str(char* _str) {
+ return record_match_from_array(_str, record_classes, record_classes_len);
+}
+
+uint16_t record_type_from_str(char* _str) {
+ return record_match_from_array(_str, record_types, record_types_len);
+}
+
+ssize_t record_rdata_from_str(void** _rdata, char *_str, uint16_t _rdtype) {
+ if ( _rdtype >= record_types_len )
+ return -1;
+
+ if ( !_rdata || !_str )
+ return -1;
+
+ return (*record_rdata_creator)(_str, _rdata);
+}
diff --git a/src/record.h b/src/record.h
new file mode 100644
index 0000000..ef41ecb
--- /dev/null
+++ b/src/record.h
@@ -0,0 +1,19 @@
+/*
+ * src/record.h
+ * (c) 2021 Jonas Gunz <himself@jonasgunz.de>
+ * License: MIT
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <strings.h>
+#include <sys/types.h>
+
+#include "log.h"
+
+uint16_t record_class_from_str(char* _str);
+
+uint16_t record_type_from_str(char* _str);
+
+ssize_t record_rdata_from_str(void** _rdata, char *_str, uint16_t _rdtype);
diff --git a/src/zonefile.c b/src/zonefile.c
index 07e89d7..9104ad5 100644
--- a/src/zonefile.c
+++ b/src/zonefile.c
@@ -34,6 +34,9 @@ int zonefile_parse_line(database_t *_database, char *_line) {
uint32_t ttl;
uint16_t type, class;
void* data;
+ ssize_t data_len;
+
+ void* db_entry;
memset(&parts, 0, sizeof(parts));
@@ -48,8 +51,8 @@ int zonefile_parse_line(database_t *_database, char *_line) {
LOGPRINTF(_LOG_ERROR, "FQDN Contains invalid char at pos %i", ret);
return -1;
}
- qname = malloc( (unsigned)fqdn_len+1 );
- if ( fqdn_to_qname(parts[0], fqdn_len, qname, fqdn_len+1) < 0) {
+ qname = malloc( (unsigned)fqdn_len+2 );
+ if ( fqdn_to_qname(parts[0], fqdn_len, qname, fqdn_len+2) < 0) {
LOGPRINTF(_LOG_ERROR, "Failed to convert to QNAME. This is a bug.");
return -1;
}
@@ -59,9 +62,42 @@ int zonefile_parse_line(database_t *_database, char *_line) {
return -1;
}
- DEBUG("value %s", parts[4]);
+ if ( (class = record_class_from_str(parts[2])) == 0 ) {
+ LOGPRINTF(_LOG_ERROR, "Invalid class %s", parts[2]);
+ return -1;
+ }
+
+ if ( (type = record_type_from_str(parts[3])) == 0 ) {
+ LOGPRINTF(_LOG_ERROR, "Invalid record type %s", parts[3]);
+ return -1;
+ }
+
+ if ( (data_len = record_rdata_from_str(&data, parts[4], type)) <= 0 ) {
+ LOGPRINTF(_LOG_ERROR, "Invalid rdata %s", parts[4]);
+ return -1;
+ }
+
+ db_entry = malloc((unsigned)data_len + 6);
+ if ( !db_entry )
+ goto err;
+
+ DEBUG("Found %s record at %s", parts[3], parts[0]);
+
+ *((uint32_t*)db_entry) = ttl;
+ *((uint16_t*)db_entry+4) = (uint16_t) data_len;
+ strncpy(db_entry+6, data, (unsigned)data_len);
+
+ /* Error Here */
+ DEBUG("LEN: %u, %i", *( (uint16_t*)(db_entry + 4) ), data_len);
+
+ /* This breaks abstraction boundries! */
+ ret = tree_insert( &_database->zone[class-1][type-1], qname, db_entry );
+
+ free(data);
return 0;
+err:
+ free(data);
return -1;
}
@@ -87,8 +123,8 @@ int zonefile_to_database (database_t *_database, char* _file) {
DEBUG("line %u, length %li, allocated %lu", line_cnt, line_len, llen);
/* getline includes the line break. ONLY UNIX ENDINGS!! */
- if( line[line_len - 2] == '\n' )
- line[line_len - 2] = '\0';
+ if( line[line_len - 1] == '\n' )
+ line[line_len - 1] = '\0';
if ( zonefile_parse_line(_database, line) < 0) {
LOGPRINTF(_LOG_ERROR, "Error is in line %u", line_cnt)
diff --git a/src/zonefile.h b/src/zonefile.h
index 4dcd6ef..deebcf9 100644
--- a/src/zonefile.h
+++ b/src/zonefile.h
@@ -12,6 +12,7 @@
#include "database.h"
#include "log.h"
+#include "record.h"
/**
* NOT COMPATIBLE WITH STANDARD ZONEFILES!