aboutsummaryrefslogtreecommitdiff
path: root/src/record.c
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 /src/record.c
parent859843ceda93c96bf0ab20ecf5b5e5a20456ea76 (diff)
downloaddns-35c378db771ea870c4a94ffc2331b13b3522cb3c.tar.gz
add record parser
Diffstat (limited to 'src/record.c')
-rw-r--r--src/record.c193
1 files changed, 193 insertions, 0 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);
+}