From bd8e73aad283611c096f07e0fc16aa4985f9f2eb Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Fri, 30 Apr 2021 23:27:11 +0200 Subject: implemented database --- src/database.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/database.h | 66 +++++++++++++++++++++++++++++++++++ src/dns.h | 10 +++--- src/server.c | 28 ++++++++++++--- src/server.h | 4 ++- src/test.c | 43 +++++++++++++++++++---- src/test.h | 3 ++ src/tree.c | 6 ++-- src/tree.h | 2 +- src/zonefile.c | 19 ----------- src/zonefile.h | 34 ------------------ 11 files changed, 247 insertions(+), 74 deletions(-) create mode 100644 src/database.c create mode 100644 src/database.h delete mode 100644 src/zonefile.c delete mode 100644 src/zonefile.h diff --git a/src/database.c b/src/database.c new file mode 100644 index 0000000..a684cff --- /dev/null +++ b/src/database.c @@ -0,0 +1,106 @@ +/* + * src/database.c + * (c) 2021 Jonas Gunz + * License: MIT + */ + +#include "database.h" + +static int database_init ( struct database* _database ) { + // Initialize 2D array of tree_node pointers, paranoia style + if ( !( _database->zone = malloc( sizeof( struct tree_node** ) * DB_CLASS_LEN ) ) ) + return 1; + + size_t rr_size = sizeof( struct tree_node* ) * DB_RR_LEN; + for ( unsigned int i = 0; i < DB_CLASS_LEN; i++ ) { + if ( !( _database->zone[i] = malloc( rr_size ) ) ) + return 1; + + memset( _database->zone[i], 0, rr_size ); + } + + return 0; +} + +int database_populate ( + struct database* _database, + char* _zonefile +) { + if ( database_init( _database ) ) + return 1; + + // TODO parsing + + char* qname = malloc(32); + + int len = fqdn_to_qname( "test.example.com", 17, qname, 32 ); + + if ( len <= 0 ) + return 1; + + void* data = malloc( 10 ); + + *((uint32_t*)data) = 1800; + *((uint16_t*)(data+4)) = 4; + *((uint32_t*)(data+6)) = 0x45454545; + + tree_insert( &_database->zone[0][0], qname, data ); + + return 0; +} + +int database_destroy ( struct database* _database ) { + if ( !_database || !_database->zone ) + return 1; + + for ( unsigned int i = 0; i < DB_CLASS_LEN; i++ ) { + for ( unsigned int o = 0; o < DB_RR_LEN; o++ ) { + // TODO should we free data and key? + tree_destroy( &_database->zone[i][o], _TREE_FREE_DATA | _TREE_FREE_KEY ); + } + + free( _database->zone[i] ); + } + + free( _database->zone ); + _database->zone = NULL; + + return 1; +} + +int database_query ( + struct database_rdata* _rdata, + struct database* _database, + const char* _qname, + int _qname_len, + uint16_t _qtype, + uint16_t _qclass +) { + uint16_t type, class; + + // _qtype and _qclass start at 1, so they are invalid when 0. + + if ( !_rdata || !_database || !_qname || !_qtype || !_qclass || _qname_len <= 0 ) + return 1; + + if ( _qtype >= DB_RR_LEN || _qclass >= DB_RR_LEN ) + return 1; + + _rdata->ttl = 0; + _rdata->rdlen = 0; + _rdata->rdata = NULL; + + type = _qtype - 1; + class = _qclass - 1; + + void* data = tree_get( &_database->zone[class][type], _qname ); + + if ( !data ) + return 2; + + _rdata->ttl = *( (uint32_t*) data ); + _rdata->rdlen = *( (uint16_t*)(data + 4) ); + _rdata->rdata = data + 6; + + return 0; +} diff --git a/src/database.h b/src/database.h new file mode 100644 index 0000000..e6ba882 --- /dev/null +++ b/src/database.h @@ -0,0 +1,66 @@ +/* + * src/database.h + * (c) 2021 Jonas Gunz + * License: MIT + */ + +#pragma once + +#include + +#include "tree.h" + +// TODO remove +#include "dns.h" + +/* + * Structure + * + * |-CLASS_IN + * | |-RR_A tree + * | |-RR_AAAA tree + * | |-... + * |-CLASS_CS + * | |-... + * |-... + * + * !! Always substract 1 from CLASS and RR Types, they start with 1 + * + * Anything other than IN is probably never needed, but easier to do now than later. + * + * Data format in tree void* + * 0 4 6 2+len + * | ttl | len | data ... | + * ttl: uint32_t + * len: uint16_t + * + */ + +#define DB_CLASS_LEN 3 +#define DB_RR_LEN 32 + +struct database { + struct tree_node*** zone; +}; + +struct database_rdata { + char* rdata; + uint16_t rdlen; + uint32_t ttl; +}; + +int database_populate ( + struct database* _database, + char* _zonefile +); + +int database_destroy ( struct database* _database ); + +int database_query ( + struct database_rdata* _rdata, + struct database* _database, + const char* _qname, + int _qname_len, + uint16_t _qtype, + uint16_t _qclass +); diff --git a/src/dns.h b/src/dns.h index e8b55c2..4ee1c88 100644 --- a/src/dns.h +++ b/src/dns.h @@ -35,7 +35,7 @@ enum dns_record { //Record Classes #define CL_IN 1 //Internet -#define CL_CS 2 //CSNET (Onsolete) +#define CL_CS 2 //CSNET (Obsolete) #define CL_CH 3 //CHAOS #define CL_HS 4 //Hesiod enum dns_record_class { @@ -46,9 +46,9 @@ enum dns_record_class { }; //OPCODES -#define OP_Q 0 //Query -#define OP_IQ 1 //Inverse Query -#define OP_STAT 2 //Status request +#define OP_QUERY 0 //Query +#define OP_IQUERY 1 //Inverse Query +#define OP_STATUS 2 //Status request enum dns_opcode { QUERY = 0, INVERSE = 1, @@ -60,7 +60,7 @@ enum dns_opcode { #define RCODE_FORMAT 1 #define RCODE_SERVFAIL 2 #define RCODE_NAMEERR 3 -#define RCODE_NI 4 //Not implemented +#define RCODE_NOTIMPL 4 //Not implemented #define RCODE_REFUSED 5 enum dns_responsecode { NOERR = 0, diff --git a/src/server.c b/src/server.c index 1dc65a0..26b26ca 100644 --- a/src/server.c +++ b/src/server.c @@ -12,6 +12,8 @@ void run_dns_server ( server_config_t* _config ) char recv_buffer[ UDP_BUFFER_LEN ]; + struct database zone_db; + signal ( SIGTERM, signal_term ); signal ( SIGINT, signal_term ); @@ -21,6 +23,11 @@ void run_dns_server ( server_config_t* _config ) log_init_stdout ( _LOG_DEBUG ); + if ( (ret = database_populate ( &zone_db, "/nofile" )) ) { + LOGPRINTF(_LOG_ERROR, "Failed to populate database from zonefile"); + exit(1); + } + LOGPRINTF(_LOG_NOTE, "Initializing DNS Server on %s:%i", _config->bind_ip, _config->bind_port); sock_server = socket ( AF_INET, SOCK_DGRAM, 0 ); @@ -73,7 +80,8 @@ void run_dns_server ( server_config_t* _config ) &sock_client_addr, sock_client_addr_len, recv_buffer, - ret ); + ret, + &zone_db ); } close( sock_server ); @@ -83,7 +91,8 @@ int handle_connection ( int _socket, struct sockaddr_in *sockaddr_client, socklen_t sockaddr_client_len, char* _buffer, - int _bufflen ) + int _bufflen, + struct database* _zone_db ) { struct dns_message msg; @@ -98,12 +107,21 @@ int handle_connection ( int _socket, LOGPRINTF(_LOG_DEBUG, "Request for %s QTYPE %i", out, msg.question[0].qtype); } - //Always return NXDOMAIN + // Only handles first request + // TODO heavy refactoring. major POC vibe + struct database_rdata rdata; struct dns_question* quest = & msg.question[0]; - struct dns_header head = {msg.header.id,1,OP_Q,0,0,0,0,0,RCODE_NOERR,0,1,0,0}; - struct dns_answer answ = {quest->qname, quest->qname_len, RR_A, CL_IN, 69, 4, "aaa" }; + int db_ret = database_query( &rdata, _zone_db, quest->qname, quest->qname_len, quest->qtype, quest->qclass ); + if (db_ret) { + + LOGPRINTF(_LOG_DEBUG, "DB Query exited with code %i", db_ret); + return 1; + } + + struct dns_header head = {msg.header.id,1,OP_QUERY,0,0,0,0,0,RCODE_NOERR,0,1,0,0}; + struct dns_answer answ = {quest->qname, quest->qname_len, RR_A, CL_IN, rdata.ttl, rdata.rdlen, rdata.rdata }; char ret[512]; int hlen = dns_construct_header ( ret, 512, &head ); diff --git a/src/server.h b/src/server.h index d59eba6..7f74088 100644 --- a/src/server.h +++ b/src/server.h @@ -22,6 +22,7 @@ #include "dns.h" #include "log.h" +#include "database.h" #define UDP_BUFFER_LEN 512 @@ -38,6 +39,7 @@ int handle_connection ( int _socket, struct sockaddr_in *sockaddr_client, socklen_t sockaddr_client_len, char* _buffer, - int _bufflen ); + int _bufflen, + struct database* _zone_db ); void signal_term ( ); diff --git a/src/test.c b/src/test.c index 41dd197..a74edcf 100644 --- a/src/test.c +++ b/src/test.c @@ -12,12 +12,22 @@ void run_test () log_init_stdout(_LOG_DEBUG); //Space for temporary tests + test_database(); + + return; //tree_balanced_insert(NULL, NULL, NULL, 15 ); + // //Normal tests - test_tree(); - //test_dns_parsing(); - test_dns_message_fuzz(); - test_dns_qname_fuzz(); + + int ret = 0; + + ret += test_tree(); + ret += test_dns_parsing(); + ret += test_dns_message_fuzz(); + ret += test_dns_qname_fuzz(); + ret += test_database(); + + exit(ret); } int test_tree () @@ -47,11 +57,11 @@ int test_tree () printf("len_cnt %i\n", len_cnt); - tree_balanced_insert( &root, data, keys, len ); + tree_balanced_insert( &root, (void**)data, keys, len ); printf("After Insert\n"); - printf("%s\n", tree_get(&root, "aa")); + printf("%s\n", (char*)tree_get(&root, "aa")); for ( int i = 0; i < len; i++ ) { if ( strcmp( tree_get(&root, keys[i]), data[i] ) ) @@ -160,4 +170,25 @@ int test_dns_message_fuzz() return 0; } + +int test_database(){ + struct database db; + struct database_rdata rdata; + + if ( database_populate( &db, "nofile" ) ) + return 1; + + printf("Populated\n"); + + char* qname = malloc(32); + int len = fqdn_to_qname( "test.example.com.", 18, qname, 32 ); + + int ret = database_query ( &rdata, &db, qname, len, 1, 1 ); + printf("Return code %i, rdlen %i\n", ret, rdata.rdlen); + + database_destroy( &db ); + + return 0; +} + #endif diff --git a/src/test.h b/src/test.h index ea3543d..989fecf 100644 --- a/src/test.h +++ b/src/test.h @@ -8,6 +8,7 @@ #include #include "tree.h" #include "dns.h" +#include "database.h" /* * TODO @@ -28,4 +29,6 @@ int test_dns_qname_fuzz(); int test_dns_message_fuzz(); +int test_database(); + #endif diff --git a/src/tree.c b/src/tree.c index 4395c81..974a5bb 100644 --- a/src/tree.c +++ b/src/tree.c @@ -6,7 +6,7 @@ #include "tree.h" -static int string_compare ( char* _1, char* _2 ); +static int string_compare ( const char* _1, const char* _2 ); /** * ignore-case alphabetical string compare @@ -15,7 +15,7 @@ static int string_compare ( char* _1, char* _2 ); * -1 :: _1 < _2 * +1 :: _1 > _2 * */ -static int string_compare ( char* _1, char* _2 ) +static int string_compare ( const char* _1, const char* _2 ) { if ( !_1 || !_2 ) return 99; @@ -144,7 +144,7 @@ int tree_destroy ( struct tree_node** _root, uint8_t _options ) return 0; } -void* tree_get ( struct tree_node** _root, char* _query ) +void* tree_get ( struct tree_node** _root, const char* _query ) { struct tree_node** node = _root; diff --git a/src/tree.h b/src/tree.h index 2b69301..2623cb3 100644 --- a/src/tree.h +++ b/src/tree.h @@ -72,6 +72,6 @@ int tree_balanced_insert ( struct tree_node** _root, void* _data[], char* _key[ /** * Returns (void*)node->data on success, NULL on failure * */ -void* tree_get ( struct tree_node** _root, char* _query ); +void* tree_get ( struct tree_node** _root, const char* _query ); int tree_destroy( struct tree_node** _root, uint8_t _options ); diff --git a/src/zonefile.c b/src/zonefile.c deleted file mode 100644 index 7ef3535..0000000 --- a/src/zonefile.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * zonefile.c - * (c) 2019 Jonas Gunz - * License: MIT - * */ - -#include "zonefile.h" - -int zonefile_parse ( char* _filename, struct record_node* _dns_zone ) -{ - return 1; -} - -int zonefile_query ( char* _hostname, struct record_entry* _entry ) -{ - return 1; -} - - diff --git a/src/zonefile.h b/src/zonefile.h deleted file mode 100644 index 633e824..0000000 --- a/src/zonefile.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * zonefile.h - * (c) 2019 Jonas Gunz - * License: MIT - * */ - -#pragma once - -#include -#include - -#include "tree.h" - -struct record_entry { - char* name; - uint32_t ttl; - uint16_t class; - uint16_t type; - uint16_t rdlength; - char* rd; -}; - -struct record_node { - struct record_entry* rr; - struct record_node* below; - struct record_node* above; -}; - -/** - * */ -int zonefile_parse ( char* _filename, struct record_node* _dns_zone ); - -int zonefile_query ( char* _hostname, struct record_entry* _entry ); - -- cgit v1.2.3