diff options
author | Jonas Gunz <himself@jonasgunz.de> | 2019-12-02 01:37:15 +0100 |
---|---|---|
committer | Jonas Gunz <himself@jonasgunz.de> | 2019-12-02 01:37:15 +0100 |
commit | 1cd2ee4a7776fb14ca76c63ab4ed181316327ef7 (patch) | |
tree | 3908248e231cab6b731554ff491fd34733404a55 /src | |
parent | d2c641eb5b516783adfe2a236bc18412cd89af71 (diff) | |
download | dns-1cd2ee4a7776fb14ca76c63ab4ed181316327ef7.tar.gz |
Parser seems working for requests
Diffstat (limited to 'src')
-rw-r--r-- | src/dns.c | 64 | ||||
-rw-r--r-- | src/dns.h | 41 | ||||
-rw-r--r-- | src/main.c | 53 |
3 files changed, 123 insertions, 35 deletions
@@ -7,9 +7,9 @@ int dns_parse_packet ( char* _buffer, int _bufflen, struct dns_message* _msg ) if ( _bufflen < 12 ) return 1; //Too short to contain a DNS header - + //TODO test - _msg->header.id = *( (uint16_t*) _buffer ); + _msg->header.id = *( (uint16_t*) _buffer ); _msg->header.QR = ( 0x80 & *( (uint8_t*) (_buffer + 2)) ) >> 7; _msg->header.OPCODE = (0x78 & *( (uint8_t*) (_buffer + 2))) >> 3; _msg->header.AA = (0x04 & *( (uint8_t*) (_buffer + 2))) >> 2; @@ -18,17 +18,41 @@ int dns_parse_packet ( char* _buffer, int _bufflen, struct dns_message* _msg ) _msg->header.RA = (0x80 & *( (uint8_t*) (_buffer + 3))) >> 7; _msg->header.Z = (0x70 & *( (uint8_t*) (_buffer + 3))) >> 4; _msg->header.RCODE = (0x0F & *( (uint8_t*) (_buffer + 3))); - _msg->header.question_count = (*((uint8_t*) (_buffer + 4)) << 8) | *((uint8_t*) (_buffer + 5)); - _msg->header.answer_count = (*((uint8_t*) (_buffer + 6)) << 8) | *((uint8_t*) (_buffer + 7)); - _msg->header.authorative_count = (*((uint8_t*) (_buffer + 8)) << 8) | *((uint8_t*) (_buffer + 9)); + _msg->header.question_count = (*((uint8_t*) (_buffer + 4 )) << 8) | *((uint8_t*) (_buffer + 5 )); + _msg->header.answer_count = (*((uint8_t*) (_buffer + 6 )) << 8) | *((uint8_t*) (_buffer + 7 )); + _msg->header.authorative_count = (*((uint8_t*) (_buffer + 8 )) << 8) | *((uint8_t*) (_buffer + 9 )); _msg->header.additional_count = (*((uint8_t*) (_buffer + 10)) << 8) | *((uint8_t*) (_buffer + 11)); - + //TODO remove printf("ANSWER %i\n", _msg->header.answer_count); printf("QUESTI %i\n", _msg->header.question_count); printf("AUTHOR %i\n", _msg->header.authorative_count); printf("ADDITI %i\n", _msg->header.additional_count); - - return 1; + + //Allocate question array + //TODO Only implements question section. + size_t qsize = sizeof(typeof(*(_msg->question))) * _msg->question_count; + _msg->question_count = _msg->header.question_count; + _msg->question = malloc ( qsize ); + memset( _msg->question, 0, qsize ); + + int ptr = 12; //byte counter + for (int i = 0; i < _msg->question_count; i++) { + int qname_len = qname_check ( (_buffer + ptr), _bufflen - ptr); + + if (qname_len <= 0) //Check for faulty QNAME + return 1; + + _msg->question[i].qname = _buffer + ptr; + ptr += qname_len; + _msg->question[i].qtype = (uint16_t*) (_buffer + ptr); + ptr += 2; + _msg->question[i].qclass = (uint16_t*) (_buffer + ptr); + + if( ptr >= _bufflen ) //Out of bounds check + return 1; + } + + return 0; } int fqdn_to_qname( char* _source, int _sourcelen, char* _sink ,int _sinklen ) @@ -60,7 +84,7 @@ int fqdn_to_qname( char* _source, int _sourcelen, char* _sink ,int _sinklen ) _sink[lastdot] = i - lastdot; _sink[i + 1] = 0; - return i+2; + return i+2; } @@ -85,8 +109,28 @@ int qname_to_fqdn( char* _source, int _sourcelen, char* _sink, int _sinklen ) } else { _sink[i-1] = _source[i]; } + } + return i-1; +} + +int qname_check( char* _source, int _sourcelen ) +{ + if (!_sourcelen) + return -1; + int next_dot = 0; + + for (int i = 0; i < _sourcelen; i++) { + if ( i == next_dot ) { + if (_source[i]) { //Not last dot + next_dot = _source[i] + i + 1; + } else { //last dot + return i+1; + } + } else if (!_source[i]) { //Invalid qname + return -1; + } } - return i-1; + return -1; } @@ -1,18 +1,32 @@ #pragma once #include <stdint.h> +#include <stdlib.h> +#include <string.h> //TODO remove #include <stdio.h> +/** + * Data is COPIED + * */ struct dns_header; +/** + * Data is REFERENCED + * */ struct dns_question; +/** + * Data is REFERENCED + * */ struct dns_answer; /** * DNS Message struct + * + * A initialized instance is only valid as long as + * the buffer used to create it remains unchanged * */ struct dns_message; @@ -35,32 +49,33 @@ struct dns_header { }; struct dns_question { - char* qname; - uint16_t qtype; - uint16_t qclass; + const char* qname; + const uint16_t* qtype; + uint16_t* qclass; }; struct dns_answer { char* name; //in qname format - uint16_t type; - uint16_t class; - uint32_t ttl; - uint16_t rdlength; + uint16_t* type; + uint16_t* class; + uint32_t* ttl; + uint16_t* rdlength; char* rdata; }; struct dns_message { struct dns_header header; - - int qcount; + + int question_count; struct dns_question* question; - int acount; + int answer_count; struct dns_answer* answer; }; /** * Parse the packet in _buffer and populate the dns_message struct + * Struct may still be written to on failure but contents are invalid * returns: 0 on success, !=0 on failure * */ int dns_parse_packet ( char* _buffer, int _bufflen, struct dns_message* _msg ); @@ -80,3 +95,9 @@ int fqdn_to_qname( char* _source, int _sourcelen, char* _sink, int _sinklen ); * _sink may still be altered in failed attempts, but not terminated. * */ int qname_to_fqdn( char* _source, int _sourcelen, char* _sink, int _sinklen ); + +/** + * Check a QNAME and get length + * returns: length of QNAME including NULL-byte at the end, < 0 on error + * */ +int qname_check( char* _source, int _sourcelen ); @@ -34,10 +34,29 @@ void signal_term_child ( ); void signal_child ( ); -int test_main( int argc, +int main1( int argc, char* argv[] ) { printf("TEST MODE. NOT FUNCTIONAL\n"); + + /* + //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]; @@ -48,6 +67,11 @@ int test_main( int argc, 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; @@ -57,7 +81,7 @@ int test_main( int argc, printf(" %x ", out[i]); written = qname_to_fqdn (out,128,in,128); - + if (written < 0) { printf("invalid qname\n"); return 1; @@ -72,9 +96,9 @@ int test_main( int argc, int main( int argc, char* argv[] ) { - int ret; - struct sockaddr_in sock_server_addr; - + int ret; + struct sockaddr_in sock_server_addr; + char recv_buffer[ UDP_BUFFER_LEN ]; signal ( SIGTERM, signal_term ); @@ -112,7 +136,6 @@ int main( int argc, { struct sockaddr_in sock_client_addr; socklen_t sock_client_addr_len; - pid_t pid; sock_client_addr_len = sizeof ( struct sockaddr_in ); memset ( &sock_client_addr, '\0', sock_client_addr_len ); @@ -130,7 +153,7 @@ int main( int argc, LOGPRINTF(_LOG_DEBUG, "UDP Packet size %i", ret); - if ( (pid = handle_connection (sock_server, + if ( (handle_connection (sock_server, &sock_client_addr, sock_client_addr_len, recv_buffer, @@ -155,12 +178,12 @@ int handle_connection ( int _socket, int _bufflen ) { pid_t pid = fork(); - + if ( pid > 0) return 0; else if ( pid < 0 ) return errno; - + //Change signal handler. signal_term shuts down entire socket on TERM signal ( SIGTERM, signal_term_child ); @@ -169,25 +192,25 @@ int handle_connection ( int _socket, //Testing recieved question //TODO remove - char out[128]; - qname_to_fqdn((_buffer+12), _bufflen-12, out, 128); - printf("%s\n", out); - struct dns_message msg; - + if (dns_parse_packet (_buffer, _bufflen, &msg) ) { LOGPRINTF (_LOG_DEBUG, "Malformed packet recieved. parsing failed"); close ( _socket ); exit( 1 ); } + char out[128]; + qname_to_fqdn( msg.question[0].qname, 100, out, 128); + printf("%s\n", out); + exit ( 0 ); } void signal_term ( ) { printf( "Recieved Signal. Terminating active connections and closing socket\n" ); - + //terminate all children >:) kill ( 0, SIGTERM ); |