diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | src/main.c | 218 | ||||
-rw-r--r-- | src/server.c | 120 | ||||
-rw-r--r-- | src/server.h | 37 | ||||
-rw-r--r-- | src/test.c | 109 | ||||
-rw-r--r-- | src/test.h | 29 |
6 files changed, 304 insertions, 213 deletions
@@ -1,6 +1,6 @@ CC = clang CFLAGS = -Wall -LDFLAGS = +LDFLAGS = -lm BUILDDIR = build SOURCEDIR = src OBJECTDIR = obj @@ -18,7 +18,7 @@ build: dir $(OBJ) debug: CFLAGS += -g -D _DEBUG debug: build; -test: LDFLAGS += -Wl,-etest_main +test: CFLAGS += -D _TEST test: debug $(BUILDDIR)/$(OUTPUT) @@ -5,222 +5,18 @@ #include <stdio.h> #include <stdlib.h> -#include <errno.h> -#include <string.h> #include <sys/types.h> -#include <sys/socket.h> -#include <netinet/ip.h> -#include <arpa/inet.h> - -#include <unistd.h> - -#include <signal.h> - -#include "dns.h" #include "log.h" -#include "zonefile.h" - -#define PRINT_ERRNO() {printf("%s:%i %i:%s\n", __FILE__, __LINE__, errno, strerror(errno));} - -#define UDP_BUFFER_LEN 512 - -//main server socket -int sock_server; - -int handle_connection ( int _socket, - struct sockaddr_in *sockaddr_client, - socklen_t sockaddr_client_len, - char* _buffer, - int _bufflen ); - -void signal_term ( ); - -void signal_term_child ( ); - -void signal_child ( ); - -int main1( int argc, - char* argv[] ) -{ - printf("TEST MODE. NOT FUNCTIONAL\n"); - - printf ("%i\n", string_compare (argv[1], argv[2])); - - return 0; - /* - //Fuzztest the QNAME checker - FILE* urand = fopen ("/dev/urandom", "r"); - char rand[128]; - char out[129]; - out[128] = 0; - - if (!urand) - return 1; - - for (;;) { - if (fread (rand, 128, 1, urand) > 0) { - if ( qname_check(rand, 128) > 0 ) { - qname_to_fqdn ( rand, 128, out, 128); - printf("Valid %s\n", out); - } - } - }*/ - - char in[128]; - char out[128]; - - strncpy ( in, "sub.domain.example.com\0", 127); - - printf("%s\n", in); - - int written = fqdn_to_qname (in,128,out,128); - - if ( qname_check(out,128) < 0) - printf("Wrong\n"); - else - printf("qname ok\n"); - - if (written < 0) { - printf("invallid fqdn\n"); - return 1; - } - - for(int i = 0; i < written; i++) - printf(" %x ", out[i]); - - written = qname_to_fqdn (out,128,in,128); - - if (written < 0) { - printf("invalid qname\n"); - return 1; - } - - printf("%s\n", in); - - printf("\n\n"); - return 0; -} - -int main( int argc, - char* argv[] ) +int main(int argc, char* argv[]) { - int ret; - struct sockaddr_in sock_server_addr; - - char recv_buffer[ UDP_BUFFER_LEN ]; - - signal ( SIGTERM, signal_term ); - signal ( SIGINT, signal_term ); - - //Avoid zombie processes - signal (SIGCHLD, SIG_IGN); - - log_init_stdout ( _LOG_DEBUG ); - - sock_server = socket ( AF_INET, SOCK_DGRAM, 0 ); - if ( sock_server == -1 ) { - LOGPRINTF(_LOG_ERROR, "socket() failed"); - return errno; - } - - memset( &sock_server_addr, '\0', sizeof(struct sockaddr_in) ); - sock_server_addr.sin_family = AF_INET; - sock_server_addr.sin_port = htons( 53 ); - ret = inet_aton ( "0.0.0.0", & sock_server_addr.sin_addr ); - if( ret == 0 ) { //Error on 0, no errno! - LOGPRINTF(_LOG_NOTE, "inet_aton(): Invalid bind IP\n" ); - return 1; - } - - ret = bind ( sock_server, - (struct sockaddr*) &sock_server_addr, - sizeof(struct sockaddr_in) ); - if ( ret == -1 ) { - LOGPRINTF(_LOG_ERROR, "bind() failed"); - return errno; - } - - while( 1 ) - { - struct sockaddr_in sock_client_addr; - socklen_t sock_client_addr_len; - - sock_client_addr_len = sizeof ( struct sockaddr_in ); - memset ( &sock_client_addr, '\0', sock_client_addr_len ); - - ret = recvfrom (sock_server, - recv_buffer, - UDP_BUFFER_LEN, - 0, - (struct sockaddr*) &sock_client_addr, - &sock_client_addr_len ); - if ( ret == -1 ) { - LOGPRINTF( _LOG_ERROR, "recvfrom()"); - return errno; - } - - LOGPRINTF(_LOG_DEBUG, "UDP Packet size %i", ret); - - handle_connection ( sock_server, - &sock_client_addr, - sock_client_addr_len, - recv_buffer, - ret ); - } - - close( sock_server ); - - return 0; -} - -int handle_connection ( int _socket, - struct sockaddr_in *sockaddr_client, - socklen_t sockaddr_client_len, - char* _buffer, - int _bufflen ) -{ - struct dns_message msg; - - if (dns_parse_packet (_buffer, _bufflen, &msg) ) { - LOGPRINTF (_LOG_DEBUG, "Malformed packet recieved. parsing failed"); - return 1; - } - - if(msg.question_count > 0) { - char out[128]; - qname_to_fqdn( (char*) msg.question[0].qname, 100, out, 128); - printf("%s %i\n", out, msg.question[0].qtype); - } - - dns_destroy_struct ( &msg ); - - //Always return NXDOMAIN - struct dns_header head = {msg.header.id,1,OP_Q,0,0,0,0,0,NAMEERR,0,0,0,0}; - char ret[20]; - int retlen = dns_construct_header ( &head, ret, 20 ); - sendto (_socket, ret, retlen, 0, (struct sockaddr*) sockaddr_client, sockaddr_client_len); + //CMD line arg parsing goes in here +#ifdef _TEST + run_test(); +#else + run_dns_server(); +#endif - return 0; } -void signal_term ( ) { - printf( "Recieved Signal. Terminating active connections and closing socket\n" ); - - //terminate all children >:) - kill ( 0, SIGTERM ); - - shutdown ( sock_server, SHUT_RDWR ); - close ( sock_server ); - - printf( "done\n" ); - - exit( 0 ); -} - -void signal_term_child ( ) { - close ( sock_server ); - printf ( "%i: Active connection terminated\n", getpid() ); - exit( 0 ); -} diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..4ca1985 --- /dev/null +++ b/src/server.c @@ -0,0 +1,120 @@ +/* main.c + * (c) Jonas Gunz, 2020 + * License: MIT + * */ + +#include "server.h" + +void run_dns_server ( void ) +{ + int ret; + struct sockaddr_in sock_server_addr; + + char recv_buffer[ UDP_BUFFER_LEN ]; + + signal ( SIGTERM, signal_term ); + signal ( SIGINT, signal_term ); + + //Avoid zombie processes + //TODO currently useless, since no forking is done. + signal (SIGCHLD, SIG_IGN); + + log_init_stdout ( _LOG_DEBUG ); + + sock_server = socket ( AF_INET, SOCK_DGRAM, 0 ); + if ( sock_server == -1 ) { + LOGPRINTF(_LOG_ERROR, "socket() failed"); + exit ( errno ); + } + + memset( &sock_server_addr, '\0', sizeof(struct sockaddr_in) ); + sock_server_addr.sin_family = AF_INET; + sock_server_addr.sin_port = htons( 53 ); + ret = inet_aton ( "0.0.0.0", & sock_server_addr.sin_addr ); + if( ret == 0 ) { //Error on 0, no errno! + LOGPRINTF(_LOG_NOTE, "inet_aton(): Invalid bind IP\n" ); + exit ( 1 ); + } + + ret = bind ( sock_server, + (struct sockaddr*) &sock_server_addr, + sizeof(struct sockaddr_in) ); + if ( ret == -1 ) { + LOGPRINTF(_LOG_ERROR, "bind() failed"); + exit ( errno ); + } + + while( 1 ) + { + struct sockaddr_in sock_client_addr; + socklen_t sock_client_addr_len; + + sock_client_addr_len = sizeof ( struct sockaddr_in ); + memset ( &sock_client_addr, '\0', sock_client_addr_len ); + + ret = recvfrom (sock_server, + recv_buffer, + UDP_BUFFER_LEN, + 0, + (struct sockaddr*) &sock_client_addr, + &sock_client_addr_len ); + if ( ret == -1 ) { + LOGPRINTF( _LOG_ERROR, "recvfrom()"); + exit ( errno ); + } + + LOGPRINTF(_LOG_DEBUG, "UDP Packet size %i", ret); + + handle_connection ( sock_server, + &sock_client_addr, + sock_client_addr_len, + recv_buffer, + ret ); + } + + close( sock_server ); +} + +int handle_connection ( int _socket, + struct sockaddr_in *sockaddr_client, + socklen_t sockaddr_client_len, + char* _buffer, + int _bufflen ) +{ + struct dns_message msg; + + if (dns_parse_packet (_buffer, _bufflen, &msg) ) { + LOGPRINTF (_LOG_DEBUG, "Malformed packet recieved. parsing failed"); + return 1; + } + + if(msg.question_count > 0) { + char out[128]; + qname_to_fqdn( (char*) msg.question[0].qname, 100, out, 128); + printf("%s %i\n", out, msg.question[0].qtype); + } + + dns_destroy_struct ( &msg ); + + //Always return NXDOMAIN + struct dns_header head = {msg.header.id,1,OP_Q,0,0,0,0,0,NAMEERR,0,0,0,0}; + char ret[20]; + int retlen = dns_construct_header ( &head, ret, 20 ); + sendto (_socket, ret, retlen, 0, (struct sockaddr*) sockaddr_client, sockaddr_client_len); + + return 0; +} + +void signal_term ( ) { + printf( "Recieved Signal. Terminating active connections and closing socket\n" ); + + //terminate all children >:) + kill ( 0, SIGTERM ); + + shutdown ( sock_server, SHUT_RDWR ); + close ( sock_server ); + + printf( "done\n" ); + + exit( 0 ); +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..388dbae --- /dev/null +++ b/src/server.h @@ -0,0 +1,37 @@ +/* server.h + * (c) Jonas Gunz, 2020 + * License: MIT + * */ + +#pragma once + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> + +#include <sys/socket.h> +#include <netinet/ip.h> +#include <arpa/inet.h> + +#include <unistd.h> + +#include <signal.h> + +#include "dns.h" +#include "log.h" + +#define UDP_BUFFER_LEN 512 + +static int sock_server; + +void run_dns_server ( void ); + +int handle_connection ( int _socket, + struct sockaddr_in *sockaddr_client, + socklen_t sockaddr_client_len, + char* _buffer, + int _bufflen ); + +void signal_term ( ); diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..d635515 --- /dev/null +++ b/src/test.c @@ -0,0 +1,109 @@ +/* test.c + * (c) Jonas Gunz, 2020 + * License: MIT + * */ + +#include "test.h" + +#ifdef _TEST + +void run_test () +{ + //Space for temporary tests + + //tree_balanced_insert(NULL, NULL, NULL, 15 ); + //Normal tests + test_tree(); + test_dns_parsing(); + test_dns_parsing_fuzz(); +} + +int test_tree () +{ + printf("\ntest_tree()\n"); + + struct tree_node* root = NULL; + + tree_insert ( &root, "eins", "Test eins" ); + tree_insert ( &root, "zwei", "Test zwei" ); + + printf("After Insert\n"); + + printf("%s\n", tree_get(&root, "zwei")); + + printf("After Get\n"); + + tree_destroy (&root,0); + + printf("After destroy\n"); + + return 0; +} + +int test_dns_parsing () +{ + printf("test_dns_parsing()\n"); + char in[128]; + char out[128]; + + strncpy ( in, "sub.domain.example.com\0", 127); + + printf("%s\n", in); + + int written = fqdn_to_qname (in,128,out,128); + + if ( qname_check(out,128) < 0) + printf("Wrong\n"); + else + printf("qname ok\n"); + + if (written < 0) { + printf("invallid fqdn\n"); + return 1; + } + + for(int i = 0; i < written; i++) + printf(" %x ", out[i]); + + written = qname_to_fqdn (out,128,in,128); + + if (written < 0) { + printf("invalid qname\n"); + return 1; + } + + printf("%s\n", in); + + printf("\n\n"); + return 0; +} + +int test_dns_parsing_fuzz() +{ + printf("\n-> test_parsing_fuzz()\n======\n\n"); + FILE* urand = fopen ("/dev/urandom", "r"); + char rand[128]; + char out[129]; + out[128] = 0; + + if (!urand) + return 1; + + unsigned long int limit = 10000000; + unsigned long int valid_cnt = 0; + for (unsigned long int i = 0; i < limit; i++) { + if (fread (rand, 128, 1, urand) > 0) { + if ( qname_check(rand, 128) > 0 ) { + qname_to_fqdn ( rand, 128, out, 128); + //printf("Valid %s\n", out); + valid_cnt++; + } + } + } + + float valid_percent = (float)valid_cnt / (float)limit * 100; + printf("# of valid qnames in random data: %i / %i = %f%%\n", valid_cnt, limit, valid_percent); + + return 0; +} +#endif diff --git a/src/test.h b/src/test.h new file mode 100644 index 0000000..885e304 --- /dev/null +++ b/src/test.h @@ -0,0 +1,29 @@ +/* test.h + * (c) Jonas Gunz, 2020 + * License: MIT + * */ + +#pragma once + +#include <stdio.h> +#include "tree.h" +#include "dns.h" + +/* + * TODO + * * fuzz dns_parse_packet() + * * test dns_parse_packet() with random valid data + * * test qname_check() with random valid data + */ + +#ifdef _TEST + +void run_test (); + +int test_tree (); + +int test_dns_parsing (); + +int test_dns_parsing_fuzz(); + +#endif |