From 35c378db771ea870c4a94ffc2331b13b3522cb3c Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Tue, 21 Sep 2021 00:25:05 +0200 Subject: add record parser --- src/record.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 src/record.c (limited to 'src/record.c') 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 + * 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); +} -- cgit v1.2.3