aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dns.c2
-rw-r--r--src/dns.h2
-rw-r--r--src/server.c143
-rw-r--r--src/server.h11
4 files changed, 91 insertions, 67 deletions
diff --git a/src/dns.c b/src/dns.c
index 190069c..db122dd 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -26,7 +26,7 @@ int dns_construct_header ( char* _buffer, int _bufflen, dns_header_t* _header )
*((uint16_t*)(_buffer + 8 )) = FLIP_BYTES(_header->authorative_count);
*((uint16_t*)(_buffer + 10)) = FLIP_BYTES(_header->additional_count);
- return 12;
+ return DNS_HEADER_LEN;
}
int dns_construct_answer (
diff --git a/src/dns.h b/src/dns.h
index 009f861..2d5ccdf 100644
--- a/src/dns.h
+++ b/src/dns.h
@@ -71,6 +71,8 @@ enum dns_responsecode {
REFUSED = 5
};
+#define DNS_HEADER_LEN 12
+
#define FLIP_BYTES(u) (((0x00FF & u) << 8) | ((0xFF00 & u) >> 8))
/**
diff --git a/src/server.c b/src/server.c
index 8cd378a..7088dbe 100644
--- a/src/server.c
+++ b/src/server.c
@@ -7,7 +7,10 @@
void server_start ( server_config_t* _config )
{
- char recv_buffer[ UDP_BUFFER_LEN ];
+ fd_set sel_fds;
+ struct timeval sel_interval;
+ int sel_ret = 0;
+
database_t zone_db;
signal ( SIGTERM, signal_term );
@@ -23,85 +26,107 @@ void server_start ( server_config_t* _config )
LOGPRINTF(_LOG_NOTE, "Done!");
while( 1 ) {
- struct sockaddr_in sock_client_addr;
- socklen_t sock_client_addr_len = sizeof( struct sockaddr_in );
- int recv_len = 0;
-
- memset ( &sock_client_addr, 0, sock_client_addr_len );
-
- recv_len = recvfrom (sock_server,
- recv_buffer,
- UDP_BUFFER_LEN,
- 0,
- (struct sockaddr*) &sock_client_addr,
- &sock_client_addr_len );
- if ( recv_len == -1 ) {
- LOGPRINTF( _LOG_ERRNO, "recvfrom()");
- exit ( errno );
+ FD_ZERO ( &sel_fds );
+ FD_SET ( sock_server, &sel_fds );
+ sel_interval.tv_sec = 0;
+ sel_interval.tv_usec = 10000;
+
+ sel_ret = select( sock_server + 1, &sel_fds, NULL, NULL, &sel_interval );
+
+ if ( sel_ret < 0 ) {
+ LOGPRINTF( _LOG_ERRNO, "select()" );
+ exit(1);
+ } else if ( sel_ret ) {
+ // A connection is available
+ DEBUG("Connection");
+ server_handle_connection( sock_server, &zone_db );
}
-
- DEBUG("Packet size %i from %s:%i", recv_len, inet_ntoa(sock_client_addr.sin_addr), sock_client_addr.sin_port );
-
- handle_connection ( sock_server,
- &sock_client_addr,
- sock_client_addr_len,
- recv_buffer,
- recv_len,
- &zone_db );
}
close( sock_server );
exit(0);
}
-int handle_connection ( int _socket,
- struct sockaddr_in *sockaddr_client,
- socklen_t sockaddr_client_len,
- char* _buffer,
- int _bufflen,
- database_t* _zone_db ) {
- dns_message_t msg;
+void server_handle_connection ( int _socket, database_t* _zone_db ) {
+ char recv_buffer[ UDP_BUFFER_LEN ];
+ int recv_len = 0;
+
+ char answ_buffer[ UDP_BUFFER_LEN ];
+ int answ_len = UDP_BUFFER_LEN;
+ int answ_cnt = DNS_HEADER_LEN;
+ // preload with header length, because it is written last.
- if ( dns_parse_packet (_buffer, _bufflen, &msg) ) {
+ struct sockaddr_in sock_client_addr;
+ socklen_t sock_client_addr_len = sizeof( struct sockaddr_in );
+
+ dns_message_t dns_req;
+ dns_header_t answ_header;
+
+ memset ( &sock_client_addr, 0, sock_client_addr_len );
+
+ recv_len = recvfrom ( _socket, recv_buffer, UDP_BUFFER_LEN,
+ 0, (struct sockaddr*) &sock_client_addr,
+ &sock_client_addr_len );
+
+ if ( recv_len == -1 ) {
+ LOGPRINTF( _LOG_ERRNO, "recvfrom()");
+ exit ( 1 );
+ }
+
+ if ( dns_parse_packet( recv_buffer, recv_len, &dns_req ) ) {
DEBUG("Malformed packet recieved. parsing failed");
- return 1;
+ // free?
+ return;
}
- if ( ! msg.question_count ) {
+ if ( ! dns_req.question_count ) {
DEBUG("No questions in request.");
- return 1;
+ goto end;
}
- if (msg.question_count > 0) {
- char out[128];
- qname_to_fqdn( (char*) msg.question[0].qname, msg.question[0].qname_len, out, 128);
- LOGPRINTF(_LOG_DEBUG, "Request for %s QTYPE %i", out, msg.question[0].qtype);
- }
+ DEBUG("Valid data with %i question(s)", dns_req.question_count);
- // Only handles first request
- // TODO heavy refactoring. major POC vibe
+ memset ( &answ_header, 0, sizeof( dns_header_t ) );
- database_rdata_t rdata;
- dns_question_t* quest = & msg.question[0];
+ answ_header.id = dns_req.header.id;
+ answ_header.QR = 1; //Response
+ answ_header.AA = 1;
+
+ // TODO test with artificially large rdata to exceed buffer
+ for (unsigned int i = 0; i < dns_req.question_count; i++) {
+ int cnt_inc = 0;
+ database_rdata_t db_rdata;
+ dns_question_t *quest = &dns_req.question[i];
+ dns_answer_t dns_answ = {quest->qname, quest->qname_len, quest->qtype, quest->qclass, 0, 0, NULL };
- 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);
- dns_destroy_struct ( &msg );
- return 1;
- }
- dns_header_t head = {msg.header.id,1,OP_QUERY,0,0,0,0,0,RCODE_NOERR,0,1,0,0};
- dns_answer_t answ = {quest->qname, quest->qname_len, RR_A, CL_IN, rdata.ttl, rdata.rdlen, rdata.rdata };
+ if( database_query( &db_rdata, _zone_db, quest->qname, quest->qname_len, quest->qtype, quest->qclass ) ) {
+ answ_header.RCODE = RCODE_NAMEERR;
+ DEBUG("Could not answer question %i", i);
+ continue;
+ }
+
+ dns_answ.rdlength = db_rdata.rdlen;
+ dns_answ.rdata = db_rdata.rdata;
+ dns_answ.ttl = db_rdata.ttl;
+
+ cnt_inc += dns_construct_answer( &answ_buffer[answ_cnt], answ_len - answ_cnt, &dns_answ );
+
+ if (cnt_inc <= 0) {
+ LOGPRINTF(_LOG_ERROR, "dns_construct_answer() return <= 0");
+ goto end;
+ }
+
+ answ_cnt += cnt_inc;
+ answ_header.answer_count += 1;
+ }
- char ret[512];
- int hlen = dns_construct_header ( ret, 512, &head );
- int alen = dns_construct_answer ( ret + hlen, 512-hlen, &answ );
- sendto( _socket, ret, hlen + alen, 0, (struct sockaddr*) sockaddr_client, sockaddr_client_len );
+ dns_construct_header( answ_buffer, answ_len, &answ_header );
- dns_destroy_struct ( &msg );
+ sendto( _socket, answ_buffer, answ_cnt, 0, (struct sockaddr*) &sock_client_addr, sock_client_addr_len );
- return 0;
+end:
+ dns_destroy_struct ( &dns_req );
}
int server_get_socket ( char* _bind_ip, uint16_t _bind_port ) {
diff --git a/src/server.h b/src/server.h
index 1751fae..d4ecf49 100644
--- a/src/server.h
+++ b/src/server.h
@@ -20,6 +20,8 @@
#include <signal.h>
+#include <sys/select.h>
+
#include "dns.h"
#include "log.h"
#include "database.h"
@@ -37,13 +39,8 @@ static int sock_server;
void server_start ( server_config_t* _config );
-int server_get_socket ( char* _bind_ip, uint16_t _bind_port );
+void server_handle_connection ( int _socket, database_t* _zone_db );
-int handle_connection ( int _socket,
- struct sockaddr_in *sockaddr_client,
- socklen_t sockaddr_client_len,
- char* _buffer,
- int _bufflen,
- database_t* _zone_db );
+int server_get_socket ( char* _bind_ip, uint16_t _bind_port );
void signal_term ( );