Browse Source

Add systemd script

Nick Peng 7 years ago
parent
commit
7b62739c13

+ 5 - 0
etc/default/smartdns

@@ -0,0 +1,5 @@
+# Default settings for smartdns server. This file is sourced by /bin/sh from
+# /etc/init.d/smartdns.
+
+# Options to pass to smartdns
+SMART_DNS_OPTS=

+ 77 - 0
etc/init.d/smartdns

@@ -0,0 +1,77 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides:        smartdns
+# Required-Start:  $network 
+# Required-Stop:   $network 
+# Default-Start:   2 3 4 5
+# Default-Stop:
+# Short-Description: Start smartdns server
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+SMARTDNS=/usr/sbin/smartdns
+PIDFILE=/var/run/smartdns.pid
+
+test -x $SMARTDNS || exit 5
+
+case $1 in
+	start)
+		$SMARTDNS $JAIL_SHELL_OPTS
+		while true; do
+			if [ -e "$PIDFILE" ]; then
+				break;
+			fi
+			sleep .5
+		done
+		PID="`cat $PIDFILE 2>/dev/null`"
+		if [ -z "$PID" ]; then
+			echo "start smartdns server failed."
+			exit 1
+		fi
+		if [ ! -e "/proc/$PID" ]; then
+			echo "start smartdns server failed."
+			exit 1
+		fi
+		echo "start smartdns server success."
+		;;
+	stop)
+		if [ ! -f "$PIDFILE" ]; then
+			echo "smartdns server is stopped."
+			exit 0
+		fi
+		PID="`cat $PIDFILE 2>/dev/null`"
+		if [ ! -e "/proc/$PID" ] || [ -z "$PID" ]; then
+			echo "smartdns server is stopped"
+			exit 0
+		fi
+
+		kill -TERM $PID
+		if [ $? -ne 0 ]; then
+			echo "Stop smartdns server failed."
+			exit 1;
+		fi
+		rm -f $PIDFILE
+		echo "Stop smartdns server success."
+		;;
+	restart)
+		$0 stop && sleep 1 && $0 start
+		;;
+	status)
+		PID="`cat $PIDFILE 2>/dev/null`"
+		if [ ! -e "/proc/$PID" ] || [ -z "$PID" ]; then
+			echo "smartdns server is not running."
+			exit 1
+		fi
+		echo "smartdns server is running."
+		status=$?
+		;;
+	*)
+		echo "Usage: $0 {start|stop|restart|status}"
+		exit 2
+		;;
+esac
+
+exit $status
+

+ 4 - 2
smartdns.conf → etc/smartdns/smartdns.conf

@@ -5,13 +5,15 @@ bind [::]:53
 cache-size 1024
 loglevel error
 
-#server 192.168.1.1
+#server 8.8.8.8
 server 114.114.114.114
 server 123.207.137.88
 server 119.29.29.29
 server 223.5.5.5
+#BAU DNS
+server 223.113.97.99
 server 208.67.222.222:5353
 server 202.141.178.13:5353
 #server 77.88.8.8:53
 server 202.141.162.123:53
-#server 101.132.183.99:53
+#server 101.132.183.99:53

+ 204 - 0
install

@@ -0,0 +1,204 @@
+#!/bin/sh
+#
+# Copyright (C) 2018 Ruilin Peng (Nick) <[email protected]>
+#
+
+INST_DIR=$(cd $(dirname $0);pwd)
+
+showhelp()
+{
+	echo "Usage: install [OPTION]"
+	echo "Options:"
+	echo " -i               install smartdns."
+	echo " -u               uninstall smartdns."
+	echo " --prefix [dir]   prefix directory."
+	echo " -h               show this message."
+}
+
+start_service()
+{
+	if [ $ISSYSTEMD -ne 0 ]; then
+		chkconfig smartdns on
+		service smartdns start
+		return $?
+	fi
+
+	systemctl daemon-reload
+	systemctl enable smartdns
+	systemctl start smartdns
+}
+
+stop_service()
+{
+	if [ $ISSYSTEMD -ne 0 ]; then
+		service smartdns stop
+		chkconfig smartdns off
+		return 0
+	fi
+
+	systemctl stop smartdns
+	systemctl disable smartdns
+
+	return 0
+}
+
+clean_service()
+{
+	if [ $ISSYSTEMD -ne 0 ]; then
+		return 0
+	fi
+	systemctl daemon-reload
+}
+
+get_systemd_path()
+{
+	service="`systemctl --no-legend| grep .service | head -n 1 | awk '{print $1}'`"
+	SERVICE_PATH="`systemctl show $service | grep FragmentPath | awk -F'=' '{print $2}'`"
+	dirname $SERVICE_PATH
+}
+
+install_files()
+{
+	install -v -d $SMARTDNS_CONF_DIR
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+
+	install -v -m 0755 -t $PREFIX/usr/sbin src/smartdns
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+
+	install -v -m 0640 -t  $PREFIX$SMARTDNS_CONF_DIR etc/smartdns/smartdns.conf
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+
+	install -v -m 0640 -t  $PREFIX/etc/default etc/default/smartdns
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+	
+	install -v -m 0755 -t $SMARTDNS_INIT_DIR etc/init.d/smartdns 
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+
+	if [ $ISSYSTEMD -eq 0 ]; then
+		SYSTEM_UNIT_PATH="`get_systemd_path`"
+		if [ -z "$SYSTEM_UNIT_PATH" ]; then
+			return 1
+		fi
+		install -v -m 0644 -t $PREFIX$SYSTEM_UNIT_PATH systemd/smartdns.service 
+		if [ $? -ne 0 ]; then
+			return 1
+		fi
+	fi
+
+	return 0
+}
+
+uninstall_smartdns()
+{
+	if [ -z "$PREFIX" ]; then
+		stop_service
+	fi	
+	rm -f $PREFIX$SMARTDNS_CONF_DIR/smartdns.conf
+	rmdir $PREFIX$SMARTDNS_CONF_DIR
+	rm -f $PREFIX/usr/sbin/smartdns
+	rm -f $PREFIX/etc/default/smartdns
+
+	if [ $ISSYSTEMD -eq 0 ]; then
+		SYSTEM_UNIT_PATH="`get_systemd_path`"
+		if [ ! -z "$SYSTEM_UNIT_PATH" ]; then
+			rm -f $PREFIX$SYSTEM_UNIT_PATH/smartdns.service
+		fi
+	fi
+
+	if [ -z "$PREFIX" ]; then
+		clean_service
+	fi	
+}
+
+
+install_smartdns()
+{
+	local ret
+
+	install_files
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		uninstall_smartdns
+		return $ret
+	fi
+
+	if [ -z "$PREFIX" ]; then
+		start_service
+	fi
+
+	return 0
+}
+
+
+
+init_dir()
+{
+	SMARTDNS_CONF_DIR=$PREFIX/etc/smartdns
+	SMARTDNS_INIT_DIR=$PREFIX/etc/init.d
+	which systemctl >/dev/null 2>&1
+	ISSYSTEMD="$?"
+
+	cd $INST_DIR
+}
+
+main()
+{
+	ACTION=""
+
+	OPTS=`getopt -o iuh --long help,prefix: \
+		-n  "" -- "$@"`
+
+	if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+	# Note the quotes around `$TEMP': they are essential!
+	eval set -- "$OPTS"
+
+	while true; do
+		case "$1" in
+		--prefix)
+			PREFIX="$2"
+			shift 2;;
+		-h | --help )
+			showhelp
+			return 0
+			shift ;;
+		-i )
+			ACTION="INSTALL"
+			shift ;;
+		-u )
+			ACTION="UNINSTALL"
+			shift ;;
+		-- ) shift; break ;;
+		* ) break ;;
+  		esac
+	done
+
+	init_dir
+
+	if [ -z "$ACTION" ]; then
+		showhelp
+		return 0
+	elif [ "$ACTION" = "INSTALL" ]; then
+		install_smartdns
+		return $?
+	elif [ "$ACTION" = "UNINSTALL" ]; then
+		uninstall_smartdns
+		return 0
+	fi	
+
+}
+
+main $@
+exit $?
+
+

+ 1 - 1
Makefile → src/Makefile

@@ -1,7 +1,7 @@
 
 BIN=smartdns 
 OBJS=smartdns.o fast_ping.o lib/bitops.o dns_client.o dns_server.o dns.o util.o tlog.o conf.o
-CFLAGS=-g -O0 -Wall 
+CFLAGS=-g -O0 -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing 
 CFLAGS +=-Iinclude
 CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
 CXXFLAGS=-g -O0 -Wall -std=c++11 

+ 8 - 0
conf.c → src/conf.c

@@ -19,6 +19,7 @@ int dns_conf_loglevel = TLOG_ERROR;
 
 int config_bind(char *value)
 {
+	/* server bind address */
 	strncpy(dns_conf_server_ip, value, DNS_MAX_IPLEN);
 
 	return 0;
@@ -36,10 +37,12 @@ int config_server(char *value, dns_conf_server_type_t type)
 	}
 
 	server = &dns_conf_servers[index];
+	/* parse ip, port from value */
     if (parse_ip(value, server->server, &port) != 0) {
 		return -1;
     }
 
+	/* if port is not defined, set port to default 53 */
 	if (port == PORT_NOT_DEFINED) {
 		port= DEFAULT_DNS_PORT;
 	} 
@@ -68,6 +71,7 @@ int config_server_http(char *value)
 
 int config_cache_size(char *value)
 {
+	/* read dns cache size */
 	int cache_size = atoi(value);
 	if (cache_size < 0) {
 		return -1;
@@ -80,6 +84,7 @@ int config_cache_size(char *value)
 
 int config_log_level(char *value)
 {
+	/* read log level and set */
 	if (strncmp("debug", value, MAX_LINE_LEN) == 0) {
 		dns_conf_loglevel = TLOG_DEBUG;
 	} else if (strncmp("info", value, MAX_LINE_LEN) == 0) {
@@ -131,10 +136,12 @@ int load_conf(const char *file)
 			continue;
 		}
 
+		/* comment, skip */
 		if (key[0] == '#') {
 			continue;
 		}
 
+		/* if field format is not key = value, error */
 		if (filed_num != 2) {
 			goto errout;
 		}
@@ -144,6 +151,7 @@ int load_conf(const char *file)
 				continue;
 			}
 
+			/* call item function */
 			if (config_item[i].item_func(value) != 0) {
 				goto errout;
 			}

+ 0 - 0
conf.h → src/conf.h


+ 183 - 11
dns.c → src/dns.c

@@ -18,8 +18,12 @@
 
 #include "dns.h"
 #include "tlog.h"
+#include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #define QR_MASK 0x8000
 #define OPCODE_MASK 0x7800
@@ -28,25 +32,26 @@
 #define RD_MASK 0x0100
 #define RA_MASK 0x0080
 #define RCODE_MASK 0x000F
-
 #define DNS_RR_END (0XFFFF)
 
+/* read short and move pointer */
 short dns_read_short(unsigned char **buffer)
 {
 	unsigned short value;
 
 	value = ntohs(*((unsigned short *)(*buffer)));
 	*buffer += 2;
-
 	return value;
 }
 
+/* write char and move pointer */
 void dns_write_char(unsigned char **buffer, unsigned char value)
 {
 	**buffer = value;
 	*buffer += 1;
 }
 
+/* read char and move pointer */
 unsigned char dns_read_char(unsigned char **buffer)
 {
 	unsigned char value = **buffer;
@@ -54,6 +59,7 @@ unsigned char dns_read_char(unsigned char **buffer)
 	return value;
 }
 
+/* write short and move pointer */
 void dns_write_short(unsigned char **buffer, unsigned short value)
 {
 	value = htons(value);
@@ -61,6 +67,7 @@ void dns_write_short(unsigned char **buffer, unsigned short value)
 	*buffer += 2;
 }
 
+/* write int and move pointer */
 void dns_write_int(unsigned char **buffer, unsigned int value)
 {
 	value = htonl(value);
@@ -68,6 +75,7 @@ void dns_write_int(unsigned char **buffer, unsigned int value)
 	*buffer += 4;
 }
 
+/* read int and move pointer */
 unsigned int dns_read_int(unsigned char **buffer)
 {
 	unsigned int value;
@@ -78,11 +86,13 @@ unsigned int dns_read_int(unsigned char **buffer)
 	return value;
 }
 
+/* iterator get rrs begin */
 struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count)
 {
 	unsigned short start;
 	struct dns_head *head = &packet->head;
 
+	/* get rrs count by rrs type */
 	switch (type) {
 	case DNS_RRS_QD:
 		*count = head->qdcount;
@@ -105,13 +115,16 @@ struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, i
 		break;
 	}
 
+	/* if not resource record, reutrn null */
 	if (start == DNS_RR_END) {
 		return NULL;
 	}
 
+	/* return rrs data start address */
 	return (struct dns_rrs *)(packet->data + start);
 }
 
+/* iterator next rrs */
 struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs)
 {
 	if (rrs->next == DNS_RR_END) {
@@ -121,28 +134,32 @@ struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs)
 	return (struct dns_rrs *)(packet->data + rrs->next);
 }
 
+/* iterator add rrs begin */
 unsigned char *_dns_add_rrs_start(struct dns_packet *packet, int *maxlen)
 {
 	struct dns_rrs *rrs;
 	unsigned char *end = packet->data + packet->len;
+
 	rrs = (struct dns_rrs *)end;
 	*maxlen = packet->size - packet->len - sizeof(*packet);
 	if (packet->len >= packet->size - sizeof(*packet)) {
+		/* if size exceeds max packet size, return NULL */
 		return NULL;
 	}
 	return rrs->data;
 }
 
+/* iterator add rrs end */
 int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int len)
 {
 	struct dns_rrs *rrs;
 	struct dns_rrs *rrs_next;
 	struct dns_head *head = &packet->head;
 	unsigned char *end = packet->data + packet->len;
-	rrs = (struct dns_rrs *)end;
 	unsigned short *count;
 	unsigned short *start;
 
+	rrs = (struct dns_rrs *)end;
 	if (packet->len + len > packet->size - sizeof(*packet)) {
 		return -1;
 	}
@@ -169,6 +186,7 @@ int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int le
 		break;
 	}
 
+	/* add data to end of dns_packet, and set previouse rrs point to this rrs */
 	if (*start != DNS_RR_END) {
 		rrs_next = (struct dns_rrs *)(packet->data + *start);
 		while (rrs_next->next != DNS_RR_END) {
@@ -179,21 +197,29 @@ int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int le
 		*start = packet->len;
 	}
 
-	rrs->next = DNS_RR_END; //*start;
-	*count += 1;
+	/* update rrs head info */
 	rrs->len = len;
 	rrs->type = rtype;
+	rrs->next = DNS_RR_END;
+
+	/* update total data length */
+	*count += 1;
 	packet->len += len + sizeof(*rrs);
 	return 0;
 }
 
 static inline int _dns_data_left_len(struct dns_data_context *data_context)
 {
+	/* check whether data length out of bound */
 	return data_context->maxsize - (data_context->ptr - data_context->data);
 }
 
 int _dns_add_qr_head(struct dns_data_context *data_context, char *domain, int qtype, int qclass)
 {
+	/* question head */
+	/* |domain         |
+	 * |qtype | qclass |
+	 */
 	while (1) {
 		if (_dns_data_left_len(data_context) < 1) {
 			return -1;
@@ -223,7 +249,10 @@ int _dns_add_qr_head(struct dns_data_context *data_context, char *domain, int qt
 int _dns_get_qr_head(struct dns_data_context *data_context, char *domain, int maxsize, int *qtype, int *qclass)
 {
 	int i;
-
+	/* question head */
+	/* |domain         |
+	 * |qtype | qclass |
+	 */
 	for (i = 0; i < maxsize; i++) {
 		if (_dns_data_left_len(data_context) < 1) {
 			return -1;
@@ -257,6 +286,12 @@ int _dns_add_rr_head(struct dns_data_context *data_context, char *domain, int qt
 {
 	int len = 0;
 
+	/* resource record head */
+	/* |domain          |
+	 * |qtype  | qclass |
+	 * |       ttl      |
+	 * | rrlen | rrdata |
+	 */
 	len = _dns_add_qr_head(data_context, domain, qtype, qclass);
 	if (len < 0) {
 		return -1;
@@ -279,6 +314,12 @@ int _dns_get_rr_head(struct dns_data_context *data_context, char *domain, int ma
 {
 	int len = 0;
 
+	/* resource record head */
+	/* |domain          |
+	 * |qtype  | qclass |
+	 * |       ttl      |
+	 * | rrlen | rrdata |
+	 */
 	len = _dns_get_qr_head(data_context, domain, maxsize, qtype, qclass);
 
 	if (_dns_data_left_len(data_context) < 6) {
@@ -300,6 +341,12 @@ int dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_t rtype,
 	int len = 0;
 	struct dns_data_context data_context;
 
+	/* resource record */
+	/* |domain          |
+	 * |qtype  | qclass |
+	 * |       ttl      |
+	 * | rrlen | rrdata |
+	 */
 	unsigned char *data = _dns_add_rrs_start(packet, &maxlen);
 	if (data == NULL) {
 		return -1;
@@ -313,11 +360,13 @@ int dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_t rtype,
 	data_context.ptr = data;
 	data_context.maxsize = maxlen;
 
+	/* add rr head */
 	len = _dns_add_rr_head(&data_context, domain, rtype, DNS_C_IN, ttl, raw_len);
 	if (len < 0) {
 		return -1;
 	}
 
+	/* add rr data */
 	memcpy(data_context.ptr, raw, raw_len);
 	data_context.ptr += raw_len;
 	len = data_context.ptr - data_context.data;
@@ -333,12 +382,19 @@ int dns_get_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, void *
 	int ret = 0;
 	struct dns_data_context data_context;
 
+	/* resource record head */
+	/* |domain          |
+	 * |qtype  | qclass |
+	 * |       ttl      |
+	 * | rrlen | rrdata |
+	 */
 	unsigned char *data = rrs->data;
 
 	data_context.data = data;
 	data_context.ptr = data;
 	data_context.maxsize = rrs->len;
 
+	/* get rr head */
 	ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len);
 	if (ret < 0) {
 		return -1;
@@ -348,6 +404,7 @@ int dns_get_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, void *
 		return -1;
 	}
 
+	/* get rr data */
 	memcpy(raw, data_context.ptr, rr_len);
 	data_context.ptr += rr_len;
 	*raw_len = rr_len;
@@ -415,6 +472,15 @@ int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsig
 
 int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, struct dns_soa *soa)
 {
+	/* SOA */
+	/*| mname        |
+	 *| rname        |
+	 *| serial       |
+	 *| refersh      |
+	 *| retry        |
+	 *| expire       |
+	 *| minimum      |
+	 */
 	unsigned char data[sizeof(*soa)];
 	unsigned char *ptr = data;
 	int len = 0;
@@ -443,6 +509,15 @@ int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct
 	unsigned char *ptr = data;
 	int len = sizeof(data);
 
+	/* SOA */
+	/*| mname        |
+	 *| rname        |
+	 *| serial       |
+	 *| refersh      |
+	 *| retry        |
+	 *| expire       |
+	 *| minimum      |
+	 */
 	if (dns_get_RAW(rrs, domain, maxsize, ttl, data, &len) != 0) {
 		return -1;
 	}
@@ -531,6 +606,23 @@ static int _dns_decode_head(struct dns_context *context)
 		return -1;
 	}
 
+	/*
+	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                      ID                       |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                    QDCOUNT                    |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                    ANCOUNT                    |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                    NSCOUNT                    |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                    ARCOUNT                    |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	*/
+
 	head->id = dns_read_short(&context->ptr);
 	fields = dns_read_short(&context->ptr);
 	head->qr = (fields & QR_MASK) >> 15;
@@ -584,6 +676,7 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
 	unsigned char *ptr = context->ptr;
 	int is_compressed = 0;
 
+	/*[len]string[len]string...[0]0 */
 	while (1) {
 		if (ptr > context->data + context->maxsize || ptr < context->data) {
 			return -1;
@@ -595,35 +688,45 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
 			break;
 		}
 
+		/* compressed domain */
 		if (len >= 0xC0) {
+			/*
+			0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
+			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+			| 1  1|                OFFSET                   |
+			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+			*/
+			/* read offset */
 			len = dns_read_short(&ptr) & 0x3FFF;
 			if (is_compressed == 0) {
 				context->ptr = ptr;
 			}
 			ptr = context->data + len;
 			if (context->maxsize - (ptr - context->data) < 0) {
-				tlog(TLOG_ERROR, "length is not enouth %d:%d, %p, %p", context->maxsize, ptr - context->data, context->ptr, context->data);
+				tlog(TLOG_ERROR, "length is not enouth %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data), context->ptr, context->data);
 				return -1;
 			}
 			is_compressed = 1;
 			continue;
 		}
 
+		/* change [len] to '.' */
 		if (output_len > 0) {
 			*output = '.';
 			output++;
 		}
 
 		if (context->maxsize - (ptr - context->data) < 0) {
-			tlog(TLOG_ERROR, "length is not enouth %d:%d, %p, %p", context->maxsize, ptr - context->data, context->ptr, context->data);
+			tlog(TLOG_ERROR, "length is not enouth %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data), context->ptr, context->data);
 			return -1;
 		}
 
 		ptr++;
 		if (output_len < size - 1) {
+			/* copy sub string */
 			copy_len = (len < size - output_len) ? len : size - 1 - output_len;
 			if (context->maxsize - (ptr - context->data) < 0) {
-				tlog(TLOG_ERROR, "length is not enouth %d:%d, %p, %p", context->maxsize, ptr - context->data, context->ptr, context->data);
+				tlog(TLOG_ERROR, "length is not enouth %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data), context->ptr, context->data);
 				return -1;
 			}
 			memcpy(output, ptr, copy_len);
@@ -647,6 +750,7 @@ static int _dns_encode_domain(struct dns_context *context, char *domain)
 	int total_len = 0;
 	unsigned char *ptr_num = context->ptr++;
 
+	/*[len]string[len]string...[0]0 */
 	while (_dns_left_len(context) > 1 && *domain != 0) {
 		if (*domain == '.') {
 			*ptr_num = num;
@@ -665,6 +769,7 @@ static int _dns_encode_domain(struct dns_context *context, char *domain)
 
 	*ptr_num = num;
 	if (total_len > 0) {
+		/* if domain is '\0', [domain] is '\0' */
 		*(context->ptr) = 0;
 		context->ptr++;
 	}
@@ -674,7 +779,19 @@ static int _dns_encode_domain(struct dns_context *context, char *domain)
 static int _dns_decode_qr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass)
 {
 	int ret = 0;
-
+	/*
+	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                                               |
+	/                                               /
+	/                      NAME                     /
+	|                                               |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                      TYPE                     |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                     CLASS                     |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	*/
 	ret = _dns_decode_domain(context, domain, domain_size);
 	if (ret < 0) {
 		tlog(TLOG_ERROR, "decode domain failed.");
@@ -758,6 +875,27 @@ static int _dns_encode_raw(struct dns_context *context, struct dns_rrs *rrs)
 	char domain[DNS_MAX_CNAME_LEN];
 	int rr_len;
 	struct dns_data_context data_context;
+	/*
+	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                                               |
+	/                                               /
+	/                      NAME                     /
+	|                                               |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                      TYPE                     |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                     CLASS                     |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                      TTL                      |
+	|                                               |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	|                   RDLENGTH                    |
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+	/                     RDATA                     /
+	/                                               /
+	+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+	*/
 
 	data_context.data = rrs->data;
 	data_context.ptr = rrs->data;
@@ -968,6 +1106,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
 	struct dns_packet *packet = context->packet;
 	unsigned char *start;
 
+	/* decode rr head */
 	ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
 	if (ret < 0) {
 		tlog(TLOG_ERROR, "decode head failed.");
@@ -975,6 +1114,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
 	}
 	start = context->ptr;
 
+	/* decode answer */
 	switch (qtype) {
 	case DNS_T_A: {
 		unsigned char addr[DNS_RR_A_LEN];
@@ -1067,7 +1207,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
 	}
 
 	if (context->ptr - start != rr_len) {
-		tlog(TLOG_ERROR, "length mitchmatch , %s, %d:%d", domain, context->ptr - start, rr_len);
+		tlog(TLOG_ERROR, "length mitchmatch , %s, %ld:%d", domain, (long)(context->ptr - start), rr_len);
 		return -1;
 	}
 
@@ -1297,3 +1437,35 @@ int dns_encode(unsigned char *data, int size, struct dns_packet *packet)
 
 	return context.ptr - context.data;
 }
+
+void dns_debug(void)
+{
+	unsigned char data[1024];
+	int len;
+	char buff[4096];
+
+	int fd = open("dns.bin", O_RDWR);
+	if (fd < 0) {
+		return;
+	}
+	len = read(fd, data, 1024);
+	close(fd);
+	if (len < 0) {
+		return;
+	}
+
+	struct dns_packet *packet = (struct dns_packet *)buff;
+	if (dns_decode(packet, 4096, data, len) != 0) {
+		tlog(TLOG_ERROR, "decode failed.\n");
+	}
+
+	memset(data, 0, sizeof(data));
+	len = dns_encode(data, 1024, packet);
+	if (len < 0) {
+		tlog(TLOG_ERROR, "encode failed.\n");
+	}
+
+	fd = open("dns-cmp.bin", O_CREAT | O_TRUNC | O_RDWR);
+	write(fd, data, len);
+	close(fd);
+}

+ 15 - 17
dns.h → src/dns.h

@@ -9,8 +9,8 @@
 #define DNS_RR_A_LEN 4
 #define DNS_RR_AAAA_LEN 16
 #define DNS_MAX_CNAME_LEN 256
-#define DNS_IN_PACKSIZE (512 * 2)
-#define DNS_PACKSIZE (512 * 4)
+#define DNS_IN_PACKSIZE (512 * 4)
+#define DNS_PACKSIZE (512 * 8)
 
 typedef enum dns_qr {
 	DNS_QR_QUERY = 0,
@@ -68,8 +68,9 @@ typedef enum dns_rtcode {
 	DNS_RC_BADVERS = 16,
 } dns_rtcode_t; /* dns_rcode */
 
+/* dns packet head */
 struct dns_head {
-	unsigned short id;      // identification number
+	unsigned short id;      /* identification number */
 	unsigned short qr;      /* Query/Response Flag */
 	unsigned short opcode;  /* Operation Code */
 	unsigned char aa;       /* Authoritative Answer Flag */
@@ -77,10 +78,10 @@ struct dns_head {
 	unsigned char rd;       /* Recursion Desired */
 	unsigned char ra;       /* Recursion Available */
 	unsigned short rcode;   /* Response Code */
-	unsigned short qdcount; // number of question entries
-	unsigned short ancount; // number of answer entries
-	unsigned short nscount; // number of authority entries
-	unsigned short nrcount; // number of addititional resource entries
+	unsigned short qdcount; /* number of question entries */
+	unsigned short ancount; /* number of answer entries */
+	unsigned short nscount; /* number of authority entries */
+	unsigned short nrcount; /* number of addititional resource entries */
 } __attribute__((packed));
 
 struct dns_rrs {
@@ -90,6 +91,7 @@ struct dns_rrs {
 	unsigned char data[0];
 };
 
+/* packet haed */
 struct dns_packet {
 	struct dns_head head;
 	unsigned short questions;
@@ -101,12 +103,14 @@ struct dns_packet {
 	unsigned char data[0];
 };
 
+/* RRS encode/decode context */
 struct dns_data_context {
 	unsigned char *data;
 	unsigned char *ptr;
 	unsigned int maxsize;
 };
 
+/* packet encode/decode context */
 struct dns_context {
 	struct dns_packet *packet;
 	unsigned char *data;
@@ -114,6 +118,7 @@ struct dns_context {
 	unsigned char *ptr;
 };
 
+/* SOA data */
 struct dns_soa {
 	char mname[DNS_MAX_CNAME_LEN];
 	char rname[DNS_MAX_CNAME_LEN];
@@ -122,48 +127,41 @@ struct dns_soa {
 	unsigned int retry;
 	unsigned int expire;
 	unsigned int minimum;
-} __attribute__((packed));;
+} __attribute__((packed));
+;
 
 struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs);
-
 struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count);
 
 /*
  * Question
  */
 int dns_add_domain(struct dns_packet *packet, char *domain, int qtype, int qclass);
-
 int dns_get_domain(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *qclass);
 
 /*
  * Answers
  */
 int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname);
-
 int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
 
 int dns_add_A(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[DNS_RR_A_LEN]);
-
 int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_A_LEN]);
 
 int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname);
-
 int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
 
 int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[DNS_RR_AAAA_LEN]);
-
 int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_AAAA_LEN]);
 
 int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, struct dns_soa *soa);
-
 int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_soa *soa);
 /*
  * Packet operation
  */
 int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int size);
-
 int dns_encode(unsigned char *data, int size, struct dns_packet *packet);
 
 int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head);
 
-#endif
+#endif

+ 94 - 58
dns_client.c → src/dns_client.c

@@ -44,40 +44,41 @@
 #include <unistd.h>
 
 #define DNS_MAX_HOSTNAME 256
-
 #define DNS_MAX_EVENTS 64
-
 #define DNS_HOSTNAME_LEN 128
 
-struct dns_query_server {
-	int fd;
-	int type;
-	char host[DNS_HOSTNAME_LEN];
-	struct list_head list;
-};
-
+/* dns client */
 struct dns_client {
 	pthread_t tid;
 	int run;
 	int epoll_fd;
 
+	/* dns server list */
 	pthread_mutex_t server_list_lock;
 	struct list_head dns_server_list;
 
+	/* query list */
 	pthread_mutex_t dns_request_lock;
 	struct list_head dns_request_list;
-	struct list_head dns_request_wait_list;
 
+	/* query doman hash table, key: sid + domain */
 	pthread_mutex_t domain_map_lock;
 	DECLARE_HASHTABLE(domain_map, 6);
 
+	/* client socket */
 	int udp;
 };
 
+/* dns server information */
 struct dns_server_info {
 	struct list_head list;
+	/* server ping handle */
 	struct ping_host_struct *ping_host;
+
+	/* server type */
 	dns_server_type_t type;
+
+	/* server addr info */
 	unsigned short ss_family;
 	socklen_t addr_len;
 	union {
@@ -87,6 +88,7 @@ struct dns_server_info {
 	};
 };
 
+/* dns replied server info */
 struct dns_query_replied {
 	struct hlist_node node;
 	socklen_t addr_len;
@@ -97,25 +99,36 @@ struct dns_query_replied {
 	};
 };
 
+/* query struct */
 struct dns_query_struct {
 	atomic_t refcnt;
+	/* query id, hash key sid + domain*/
+	char domain[DNS_MAX_CNAME_LEN];
 	unsigned short sid;
+	struct hlist_node domain_node;
+
 	struct list_head dns_request_list;
 	struct list_head period_list;
-	struct hlist_node domain_node;
-	char domain[DNS_MAX_CNAME_LEN];
+
+	/* dns query type */
 	int qtype;
+
+	/* dns query number */
 	atomic_t dns_request_sent;
-	void *user_ptr;
 	unsigned long send_tick;
+
+	/* caller notification */
 	dns_client_callback callback;
+	void *user_ptr;
 
+	/* replied hash table */
 	DECLARE_HASHTABLE(replied_map, 4);
 };
 
 static struct dns_client client;
 static atomic_t dns_client_sid = ATOMIC_INIT(0);
 
+/* get addr info */
 static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol)
 {
 	struct addrinfo hints;
@@ -142,6 +155,7 @@ errout:
 	return NULL;
 }
 
+/* check whether server exists */
 int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t server_type)
 {
 	struct dns_server_info *server_info, *tmp;
@@ -159,13 +173,16 @@ int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t server_type
 		if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) {
 			continue;
 		}
+
 		pthread_mutex_lock(&client.server_list_lock);
 		return 0;
 	}
+
 	pthread_mutex_unlock(&client.server_list_lock);
 	return -1;
 }
 
+/* add dns server information */
 int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type)
 {
 	struct dns_server_info *server_info = NULL;
@@ -183,16 +200,18 @@ int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_typ
 	server_info->addr_len = gai->ai_addrlen;
 	server_info->type = server_type;
 	if (gai->ai_addrlen > sizeof(server_info->in6)) {
-		tlog(TLOG_ERROR, "addr len invalid, %d, %d, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ss_family);
+		tlog(TLOG_ERROR, "addr len invalid, %d, %zd, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ss_family);
 		goto errout;
 	}
 	memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen);
 
+	/* start ping task */
 	server_info->ping_host = fast_ping_start(server_ip, 0, 60000, 1000, NULL, server_info);
 	if (server_info->ping_host == NULL) {
 		goto errout;
 	}
 
+	/* add to list */
 	pthread_mutex_lock(&client.server_list_lock);
 	list_add(&server_info->list, &client.dns_server_list);
 	pthread_mutex_unlock(&client.server_list_lock);
@@ -208,6 +227,7 @@ errout:
 	return -1;
 }
 
+/* remove all servers information */
 void _dns_client_server_remove_all(void)
 {
 	struct dns_server_info *server_info, *tmp;
@@ -215,6 +235,7 @@ void _dns_client_server_remove_all(void)
 	list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list)
 	{
 		list_del(&server_info->list);
+		/* stop ping task */
 		if (fast_ping_stop(server_info->ping_host) != 0) {
 			tlog(TLOG_ERROR, "stop ping failed.\n");
 		}
@@ -223,9 +244,12 @@ void _dns_client_server_remove_all(void)
 	pthread_mutex_unlock(&client.server_list_lock);
 }
 
+/* remove single server */
 int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type)
 {
 	struct dns_server_info *server_info, *tmp;
+
+	/* find server and remove */
 	pthread_mutex_lock(&client.server_list_lock);
 	list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list)
 	{
@@ -265,6 +289,7 @@ int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t serv
 		sock_type = SOCK_STREAM;
 	}
 
+	/* get addr info */
 	snprintf(port_s, 8, "%d", port);
 	gai = _dns_client_getaddr(server_ip, port_s, sock_type, 0);
 	if (gai == NULL) {
@@ -317,10 +342,12 @@ void _dns_client_query_release(struct dns_query_struct *query)
 		return;
 	}
 
+	/* notify caller query end */
 	if (query->callback) {
 		query->callback(query->domain, DNS_QUERY_END, NULL, NULL, 0, query->user_ptr);
 	}
 
+	/* free resource */
 	pthread_mutex_lock(&client.domain_map_lock);
 	list_del_init(&query->dns_request_list);
 	hash_del(&query->domain_node);
@@ -337,6 +364,7 @@ void _dns_client_query_release(struct dns_query_struct *query)
 
 void _dns_client_query_remove(struct dns_query_struct *query)
 {
+	/* remove query from period check list, and release reference*/
 	pthread_mutex_lock(&client.domain_map_lock);
 	list_del_init(&query->dns_request_list);
 	hash_del(&query->domain_node);
@@ -371,12 +399,14 @@ void _dns_client_query_get(struct dns_query_struct *query)
 	atomic_inc(&query->refcnt);
 }
 
-void _dns_client_period_run()
+void _dns_client_period_run(void)
 {
 	struct dns_query_struct *query, *tmp;
 	LIST_HEAD(check_list);
 
 	unsigned long now = get_tick_count();
+
+	/* get query which timed out to check list */ 
 	pthread_mutex_lock(&client.domain_map_lock);
 	list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list)
 	{
@@ -389,6 +419,7 @@ void _dns_client_period_run()
 
 	list_for_each_entry_safe(query, tmp, &check_list, period_list)
 	{
+		/* free timed out query, and notify caller */
 		list_del_init(&query->period_list);
 		_dns_client_query_remove(query);
 		_dns_client_query_release(query);
@@ -399,9 +430,11 @@ void _dns_client_period_run()
 static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char *domain)
 {
 	struct dns_query_struct *query = NULL;
+	struct dns_query_struct *query_result = NULL;
 	struct hlist_node *tmp = NULL;
 	unsigned int key;
 
+	/* get query by hash key : id + domain */
 	key = hash_string(domain);
 	key = jhash(&sid, sizeof(sid), key);
 	pthread_mutex_lock(&client.domain_map_lock);
@@ -410,11 +443,16 @@ static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char
 		if (strncmp(query->domain, domain, DNS_MAX_CNAME_LEN) != 0) {
 			continue;
 		}
+
+		if (sid != query->sid) {
+			continue;
+		}
+		query_result = query;
 		break;
 	}
 	pthread_mutex_unlock(&client.domain_map_lock);
 
-	return query;
+	return query_result;
 }
 
 int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *addr, socklen_t addr_len)
@@ -427,9 +465,11 @@ int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *
 		return -1;
 	}
 
+	/* avoid multiple replies from one server */
 	key = jhash(addr, addr_len, 0);
 	hash_for_each_possible(dns_query->replied_map, replied_map, node, key)
 	{
+		/* already replied, ignore this reply */
 		if (memcmp(&replied_map->addr, addr, addr_len) == 0) {
 			return -1;
 		}
@@ -441,6 +481,7 @@ int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *
 		return -1;
 	}
 
+	/* add address info to check hashtable */
 	memcpy(&replied_map->addr, addr, addr_len);
 	hash_add(dns_query->replied_map, &replied_map->node, key);
 	return 0;
@@ -462,12 +503,15 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
 	int request_num = 0;
 
 	packet->head.tc = 0;
+
+	/* decode domain from udp packet */
 	len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len);
 	if (len != 0) {
 		tlog(TLOG_ERROR, "decode failed, packet len = %d, tc=%d, %d\n", inpacket_len, packet->head.tc, packet->head.id);
 		return -1;
 	}
 
+	/* not answer, return error */
 	if (packet->head.qr != DNS_OP_IQUERY) {
 		tlog(TLOG_ERROR, "message type error.\n");
 		return -1;
@@ -477,17 +521,20 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
 		 packet->head.ancount, packet->head.nscount, packet->head.nrcount, inpacket_len, packet->head.id, packet->head.tc, packet->head.rd, packet->head.ra,
 		 packet->head.rcode);
 
+	/* get question */
 	rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &rr_count);
 	for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
 		dns_get_domain(rrs, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass);
 		tlog(TLOG_DEBUG, "domain: %s qtype: %d  qclass: %d\n", domain, qtype, qclass);
 	}
 
+	/* get query reference */
 	query = _dns_client_get_request(packet->head.id, domain);
 	if (query == NULL) {
 		return 0;
 	}
 
+	/* avoid multiple replies */
 	if (_dns_replied_check_add(query, (struct sockaddr *)from, from_len) != 0) {
 		return 0;
 	}
@@ -498,13 +545,15 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
 		return -1;
 	}
 
+	/* notify caller dns query result */
 	if (query->callback) {
 		ret = query->callback(query->domain, DNS_QUERY_RESULT, packet, inpacket, inpacket_len, query->user_ptr);
 	}
 
 	if (request_num == 0 || ret) {
+		/* if all server replied, or done, stop query, release resource */
 		_dns_client_query_remove(query);
-	}
+	} 
 
 	return ret;
 }
@@ -517,6 +566,7 @@ static int _dns_client_process(struct dns_query_struct *dns_query, unsigned long
 	socklen_t from_len = sizeof(from);
 	char from_host[DNS_MAX_CNAME_LEN];
 
+	/* receive from udp */
 	len = recvfrom(client.udp, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
 	if (len < 0) {
 		tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
@@ -526,9 +576,6 @@ static int _dns_client_process(struct dns_query_struct *dns_query, unsigned long
 	tlog(TLOG_DEBUG, "recv from %s", gethost_by_addr(from_host, (struct sockaddr *)&from, from_len));
 
 	if (_dns_client_recv(inpacket, len, &from, from_len) != 0) {
-		int fd = open("dns.bin", O_CREAT | O_TRUNC | O_RDWR);
-		write(fd, inpacket, len);
-		close(fd);
 		return -1;
 	}
 
@@ -590,21 +637,35 @@ static int _dns_client_send_udp(struct dns_server_info *server_info, void *packe
 	return 0;
 }
 
+static int _dns_client_send_tcp(struct dns_server_info *server_info, void *packet, int len)
+{
+	return -1;
+}
+
+
 static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, int len)
 {
 	struct dns_server_info *server_info, *tmp;
 	int ret = 0;
 
 	query->send_tick = get_tick_count();
+
+	/* send query to all dns servers */
 	pthread_mutex_lock(&client.server_list_lock);
 	list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list)
 	{
 		atomic_inc(&query->dns_request_sent);
 		switch (server_info->type) {
 		case DNS_SERVER_UDP:
+			/* udp query */
 			ret = _dns_client_send_udp(server_info, packet, len);
 			break;
+		case DNS_SERVER_TCP:
+			/* tcp query */
+			ret = _dns_client_send_tcp(server_info, packet, len);
+			break;
 		default:
+			/* unsupport query type */
 			ret = -1;
 			break;
 		}
@@ -627,6 +688,7 @@ static int _dns_client_send_query(struct dns_query_struct *query, char *doamin)
 	struct dns_packet *packet = (struct dns_packet *)packet_buff;
 	int encode_len;
 
+	/* init dns packet head */
 	struct dns_head head;
 	memset(&head, 0, sizeof(head));
 	head.id = query->sid;
@@ -638,13 +700,18 @@ static int _dns_client_send_query(struct dns_query_struct *query, char *doamin)
 	head.rcode = 0;
 
 	dns_packet_init(packet, DNS_PACKSIZE, &head);
+
+	/* add question */
 	dns_add_domain(packet, doamin, query->qtype, DNS_C_IN);
+
+	/* encode packet */
 	encode_len = dns_encode(inpacket, DNS_IN_PACKSIZE, packet);
 	if (encode_len <= 0) {
 		tlog(TLOG_ERROR, "encode query failed.");
 		return -1;
 	}
 
+	/* send query packet */
 	return _dns_client_send_packet(query, inpacket, encode_len);
 }
 
@@ -659,6 +726,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
 		goto errout;
 	}
 	memset(query, 0, sizeof(*query));
+
 	INIT_HLIST_NODE(&query->domain_node);
 	INIT_LIST_HEAD(&query->dns_request_list);
 	atomic_set(&query->refcnt, 0);
@@ -672,6 +740,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
 	query->sid = atomic_inc_return(&dns_client_sid);
 
 	_dns_client_query_get(query);
+	/* add query to hashtable */
 	key = hash_string(domain);
 	key = jhash(&query->sid, sizeof(query->sid), key);
 	pthread_mutex_lock(&client.domain_map_lock);
@@ -679,6 +748,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
 	hash_add(client.domain_map, &query->domain_node, key);
 	pthread_mutex_unlock(&client.domain_map_lock);
 
+	/* send query */
 	ret = _dns_client_send_query(query, domain);
 	if (ret != 0) {
 		goto errout_del_list;
@@ -701,11 +771,6 @@ errout:
 	return -1;
 }
 
-int dns_client_query_raw(char *domain, int qtype, unsigned char *raw, int raw_len, void *user_ptr)
-{
-	return -1;
-}
-
 static struct addrinfo *_dns_server_getaddr(const char *host, const char *port, int type, int protocol)
 {
 	struct addrinfo hints;
@@ -748,6 +813,7 @@ int dns_client_socket(void)
 	int fd = -1;
 	struct addrinfo *gai = NULL;
 
+	/* create udp socket */
 	gai = _dns_server_getaddr(NULL, "53", SOCK_DGRAM, 0);
 	if (gai == NULL) {
 		tlog(TLOG_ERROR, "get address failed.\n");
@@ -775,38 +841,6 @@ errout:
 	return -1;
 }
 
-void dns_debug(void)
-{
-	unsigned char data[1024];
-	int len;
-	char buff[4096];
-
-	int fd = open("dns.bin", O_RDWR);
-	if (fd < 0) {
-		return;
-	}
-	len = read(fd, data, 1024);
-	close(fd);
-	if (len < 0) {
-		return;
-	}
-
-	struct dns_packet *packet = (struct dns_packet *)buff;
-	if (dns_decode(packet, 4096, data, len) != 0) {
-		tlog(TLOG_ERROR, "decode failed.\n");
-	}
-
-	memset(data, 0, sizeof(data));
-	len = dns_encode(data, 1024, packet);
-	if (len < 0) {
-		tlog(TLOG_ERROR, "encode failed.\n");
-	}
-
-	fd = open("dns-cmp.bin", O_CREAT | O_TRUNC | O_RDWR);
-	write(fd, data, len);
-	close(fd);
-}
-
 int dns_client_init()
 {
 	pthread_attr_t attr;
@@ -838,12 +872,13 @@ int dns_client_init()
 
 	pthread_mutex_init(&client.domain_map_lock, 0);
 	hash_init(client.domain_map);
-	INIT_LIST_HEAD(&client.dns_request_wait_list);
 	INIT_LIST_HEAD(&client.dns_request_list);
 
 	client.epoll_fd = epollfd;
 	client.run = 1;
 	client.udp = fd;
+
+	/* start work task */
 	ret = pthread_create(&client.tid, &attr, _dns_client_work, NULL);
 	if (ret != 0) {
 		tlog(TLOG_ERROR, "create client work thread failed, %s\n", strerror(errno));
@@ -890,6 +925,7 @@ void dns_client_exit()
 		close(client.udp);
 	}
 
+	/* free all resouces */
 	_dns_client_server_remove_all();
 	_dns_client_query_remove_all();
 

+ 4 - 2
dns_client.h → src/dns_client.h

@@ -18,16 +18,18 @@ typedef enum dns_result_type {
 
 int dns_client_init(void);
 
+/* query result notify function */
 typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len, void *user_ptr);
 
+/* query domain */
 int dns_client_query(char *domain, int qtype, dns_client_callback callback, void *user_ptr);
 
-int dns_client_query_raw(char *domain, int qtype, unsigned char *raw, int raw_len, void *user_ptr);
-
 void dns_client_exit(void);
 
+/* add remote dns server */
 int dns_add_server(char *server_ip, int port, dns_server_type_t server_type);
 
+/* remove remote dns server */
 int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type);
 
 #endif

+ 17 - 3
dns_server.c → src/dns_server.c

@@ -49,16 +49,18 @@
 
 #define DNS_MAX_EVENTS 256
 
+/* dns server data */
 struct dns_server {
 	int run;
 	int epoll_fd;
-
 	int fd;
 
+	/* dns request list */
 	pthread_mutex_t request_list_lock;
 	struct list_head request_list;
 };
 
+/* ip address lists of domain */
 struct dns_ip_address {
 	struct hlist_node node;
 	dns_type_t addr_type;
@@ -71,9 +73,13 @@ struct dns_ip_address {
 
 struct dns_request {
 	atomic_t refcnt;
+	/* dns request list */
 	struct list_head list;
+
+	/* dns request timeout check list */
 	struct list_head check_list;
 
+	/* dns query */
 	char domain[DNS_MAX_CNAME_LEN];
 	struct dns_head head;
 	unsigned long send_tick;
@@ -90,7 +96,6 @@ struct dns_request {
 
 	int has_ping_result;
 	int has_ping_tcp;
-
 	int has_ptr;
 
 	int has_cname;
@@ -109,6 +114,7 @@ struct dns_request {
 
 	atomic_t notified;
 
+	/* send original raw packet to server/client like proxy */
 	int passthrough;
 
 	pthread_mutex_t ip_map_lock;
@@ -464,6 +470,10 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 			switch (rrs->type) {
 			case DNS_T_A: {
 				unsigned char addr[4];
+				if (request->qtype != DNS_T_A) {
+					/* ignore non-matched query type */
+					break;
+				}
 				_dns_server_request_get(request);
 				dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
 
@@ -496,6 +506,10 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 			} break;
 			case DNS_T_AAAA: {
 				unsigned char addr[16];
+				if (request->qtype != DNS_T_AAAA) {
+					/* ignore non-matched query type */
+					break;
+				}
 				_dns_server_request_get(request);
 				dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
 
@@ -808,7 +822,7 @@ void _dns_server_tcp_ping_check(struct dns_request *request)
 	request->has_ping_tcp = 1;
 }
 
-void _dns_server_period_run()
+void _dns_server_period_run(void)
 {
 	struct dns_request *request, *tmp;
 	LIST_HEAD(check_list);

+ 0 - 0
dns_server.h → src/dns_server.h


+ 3 - 3
fast_ping.c → src/fast_ping.c

@@ -891,7 +891,7 @@ static void _fast_ping_remove_all(void)
 	}
 }
 
-static void _fast_ping_period_run()
+static void _fast_ping_period_run(void)
 {
 	struct ping_host_struct *ping_host = NULL;
 	struct ping_host_struct *ping_host_tmp = NULL;
@@ -1002,7 +1002,7 @@ static void *_fast_ping_work(void *arg)
 	return NULL;
 }
 
-int fast_ping_init()
+int fast_ping_init(void)
 {
 	pthread_attr_t attr;
 	int epollfd = -1;
@@ -1051,7 +1051,7 @@ errout:
 	return -1;
 }
 
-void fast_ping_exit()
+void fast_ping_exit(void)
 {
 	if (ping.tid > 0) {
 		void *ret = NULL;

+ 4 - 2
fast_ping.h → src/fast_ping.h

@@ -23,13 +23,15 @@ typedef enum {
 struct ping_host_struct;
 typedef void (*fast_ping_result)(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr);
 
+/* start ping */
 struct ping_host_struct *fast_ping_start(const char *host, int count, int interval, int timeout, fast_ping_result ping_callback, void *userptr);
 
+/* stop ping */
 int fast_ping_stop(struct ping_host_struct *ping_host);
 
-int fast_ping_init();
+int fast_ping_init(void);
 
-void fast_ping_exit();
+void fast_ping_exit(void);
 
 #ifdef __cpluscplus
 }

+ 0 - 0
include/atomic.h → src/include/atomic.h


+ 0 - 0
include/bitmap.h → src/include/bitmap.h


+ 0 - 0
include/bitops.h → src/include/bitops.h


+ 0 - 0
include/cache.h → src/include/cache.h


+ 0 - 0
include/findbit.h → src/include/findbit.h


+ 0 - 0
include/gcc_builtin.h → src/include/gcc_builtin.h


+ 0 - 0
include/hash.h → src/include/hash.h


+ 0 - 0
include/hashtable.h → src/include/hashtable.h


+ 0 - 0
include/jhash.h → src/include/jhash.h


+ 0 - 0
include/list.h → src/include/list.h


+ 0 - 0
lib/bitops.c → src/lib/bitops.c


+ 0 - 0
lib/cache.c → src/lib/cache.c


+ 106 - 8
smartdns.c → src/smartdns.c

@@ -26,14 +26,36 @@
 #include "tlog.h"
 #include "util.h"
 #include <errno.h>
+#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #define RESOLVE_FILE "/etc/resolv.conf"
 #define MAX_LINE_LEN 1024
 #define MAX_KEY_LEN 64
+#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
+#define SMARTDNS_LOG_PATH "/var/log"
+#define SMARTDNS_LOG_FILE "smartdns.log"
+#define SMARTDNS_PID_FILE "/var/run/smartdns.pid"
+#define TMP_BUFF_LEN_32 32
+
+void help(void)
+{
+	/* clang-format off */
+	char *help = ""
+		"Usage: smartdns [OPTION]...\n"
+		"Start smartdns server.\n"
+		"  -f            run forground.\n"
+		"  -c [conf]     config file.\n"
+		"  -h            show this help message.\n"
+		"\n";
+	/* clang-format on */
+	printf(help);
+}
 
 int smartdns_load_from_resolv(void)
 {
@@ -101,15 +123,56 @@ int smartdns_add_servers(void)
 	return 0;
 }
 
-int smartdns_init()
+int create_pid_file(const char *pid_file)
 {
-	int ret;
+	int fd;
+	int flags;
+	char buff[TMP_BUFF_LEN_32];
+
+	/*  create pid file, and lock this file */
+	fd = open(pid_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+	if (fd == -1) {
+		fprintf(stderr, "create pid file failed, %s", strerror(errno));
+		return -1;
+	}
 
-	if (load_conf("smartdns.conf") != 0) {
-		fprintf(stderr, "load config failed.");
+	flags = fcntl(fd, F_GETFD);
+	if (flags < 0) {
+		fprintf(stderr, "Could not get flags for PID file %s", pid_file);
+		goto errout;
+	}
+
+	flags |= FD_CLOEXEC;
+	if (fcntl(fd, F_SETFD, flags) == -1) {
+		fprintf(stderr, "Could not set flags for PID file %s", pid_file);
+		goto errout;
 	}
 
-	ret = tlog_init(".", "smartdns.log", 1024 * 1024, 8, 1, 0, 0);
+	if (lockf(fd, F_TLOCK, 0) < 0) {
+		fprintf(stderr, "Server is already running.\n");
+		goto errout;
+	}
+
+	snprintf(buff, TMP_BUFF_LEN_32, "%d\n", getpid());
+
+	if (write(fd, buff, strnlen(buff, TMP_BUFF_LEN_32)) < 0) {
+		fprintf(stderr, "write pid to file failed, %s.\n", strerror(errno));
+		goto errout;
+	}
+
+	return 0;
+errout:
+	if (fd > 0) {
+		close(fd);
+	}
+	return -1;
+}
+
+int smartdns_init(void)
+{
+	int ret;
+
+	ret = tlog_init(SMARTDNS_LOG_PATH, SMARTDNS_LOG_FILE, 1024 * 1024, 8, 1, 0, 0);
 	if (ret != 0) {
 		tlog(TLOG_ERROR, "start tlog failed.\n");
 		goto errout;
@@ -154,12 +217,12 @@ errout:
 	return -1;
 }
 
-int smartdns_run()
+int smartdns_run(void)
 {
 	return dns_server_run();
 }
 
-void smartdns_exit()
+void smartdns_exit(void)
 {
 	dns_server_exit();
 	dns_client_exit();
@@ -185,11 +248,46 @@ void sig_handle(int sig)
 int main(int argc, char *argv[])
 {
 	int ret;
+	int is_forground = 0;
+	int opt;
+	char config_file[MAX_LINE_LEN];
+
+	strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
+
+	while ((opt = getopt(argc, argv, "fhc:")) != -1) {
+		switch (opt) {
+		case 'f':
+			is_forground = 1;
+			break;
+		case 'c':
+			snprintf(config_file, sizeof(config_file), optarg);
+			break;
+		case 'h':
+			help();
+			return 1;
+		}
+	}
+
+	if (is_forground == 0) {
+		if (daemon(0, 0) < 0) {
+			fprintf(stderr, "run daemon process failed, %s\n", strerror(errno));
+			return 1;
+		}
+	}
 
 	signal(SIGABRT, sig_handle);
-	
+
+	if (load_conf(config_file) != 0) {
+	}
+
+	if (create_pid_file(SMARTDNS_PID_FILE) != 0) {
+		fprintf(stderr, "create pid file failed, %s\n", strerror(errno));
+		goto errout;
+	}
+
 	ret = smartdns_init();
 	if (ret != 0) {
+		usleep(100000);
 		goto errout;
 	}
 

+ 0 - 0
tlog.c → src/tlog.c


+ 0 - 0
tlog.h → src/tlog.h


+ 1 - 1
util.c → src/util.c

@@ -5,7 +5,7 @@
 #include <string.h>
 #include <time.h>
 
-unsigned long get_tick_count()
+unsigned long get_tick_count(void)
 {
 	struct timespec ts;
 

+ 1 - 1
util.h → src/util.h

@@ -8,7 +8,7 @@
 #define PORT_NOT_DEFINED -1
 #define MAX_IP_LEN 64
 
-unsigned long get_tick_count();
+unsigned long get_tick_count(void);
 
 char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len);
 

+ 14 - 0
systemd/smartdns.service

@@ -0,0 +1,14 @@
+[Unit]
+Description=smart dns server
+After=network.target 
+
+[Service]
+PIDFile=/var/run/smartdns.pid
+EnvironmentFile=/etc/default/smartdns
+ExecStart=/usr/sbin/smartdns $SMART_DNS_OPTS
+KillMode=process
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
+Alias=smartdns.service

+ 0 - 755
test-dns.c

@@ -1,755 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <ifaddrs.h>
-#include <string.h>
-#include <malloc.h>
-#include <errno.h>
-#include <string.h>
-#include <stdint.h>
-
-#define BUF_SIZE 1500
-
-/*
-* This software is licensed under the CC0.
-*
-* This is a _basic_ DNS Server for educational use.
-* It does not prevent invalid packets from crashing
-* the server.
-*
-* To test start the program and issue a DNS request:
-*  dig @127.0.0.1 -p 9000 foo.bar.com 
-*/
-
-
-/*
-* Masks and constants.
-*/
-
-static const uint32_t QR_MASK = 0x8000;
-static const uint32_t OPCODE_MASK = 0x7800;
-static const uint32_t AA_MASK = 0x0400;
-static const uint32_t TC_MASK = 0x0200;
-static const uint32_t RD_MASK = 0x0100;
-static const uint32_t RA_MASK = 0x8000;
-static const uint32_t RCODE_MASK = 0x000F;
-
-/* Response Type */
-enum {
-  Ok_ResponseType = 0,
-  FormatError_ResponseType = 1,
-  ServerFailure_ResponseType = 2,
-  NameError_ResponseType = 3,
-  NotImplemented_ResponseType = 4,
-  Refused_ResponseType = 5
-};
-
-/* Resource Record Types */
-enum {
-  A_Resource_RecordType = 1,
-  NS_Resource_RecordType = 2,
-  CNAME_Resource_RecordType = 5,
-  SOA_Resource_RecordType = 6,
-  PTR_Resource_RecordType = 12,
-  MX_Resource_RecordType = 15,
-  TXT_Resource_RecordType = 16,
-  AAAA_Resource_RecordType = 28,
-  SRV_Resource_RecordType = 33
-};
-
-/* Operation Code */
-enum {
-  QUERY_OperationCode = 0, /* standard query */
-  IQUERY_OperationCode = 1, /* inverse query */
-  STATUS_OperationCode = 2, /* server status request */
-  NOTIFY_OperationCode = 4, /* request zone transfer */
-  UPDATE_OperationCode = 5 /* change resource records */
-};
-
-/* Response Code */
-enum {
-  NoError_ResponseCode = 0,
-  FormatError_ResponseCode = 1,
-  ServerFailure_ResponseCode = 2,
-  NameError_ResponseCode = 3
-};
-
-/* Query Type */
-enum {
-  IXFR_QueryType = 251,
-  AXFR_QueryType = 252,
-  MAILB_QueryType = 253,
-  MAILA_QueryType = 254,
-  STAR_QueryType = 255
-};
-
-/*
-* Types.
-*/
-
-/* Question Section */
-struct Question {
-  char *qName;
-  uint16_t qType;
-  uint16_t qClass;
-  struct Question* next; // for linked list
-};
-
-/* Data part of a Resource Record */
-union ResourceData {
-  struct {
-    char *txt_data;
-  } txt_record;
-  struct {
-    uint8_t addr[4];
-  } a_record;
-  struct {
-    char* MName;
-    char* RName;
-    uint32_t serial;
-    uint32_t refresh;
-    uint32_t retry;
-    uint32_t expire;
-    uint32_t minimum;
-  } soa_record;
-  struct {
-    char *name;
-  } name_server_record;
-  struct {
-    char name;
-  } cname_record;
-  struct {
-    char *name;
-  } ptr_record;
-  struct {
-    uint16_t preference;
-    char *exchange;
-  } mx_record;
-  struct {
-    uint8_t addr[16];
-  } aaaa_record;
-  struct {
-    uint16_t priority;
-    uint16_t weight;
-    uint16_t port;
-    char *target;
-  } srv_record;
-};
-
-/* Resource Record Section */
-struct ResourceRecord {
-  char *name;
-  uint16_t type;
-  uint16_t class;
-  uint16_t ttl;
-  uint16_t rd_length;
-  union ResourceData rd_data;
-  struct ResourceRecord* next; // for linked list
-};
-
-struct Message {
-  uint16_t id; /* Identifier */
-
-  /* Flags */
-  uint16_t qr; /* Query/Response Flag */
-  uint16_t opcode; /* Operation Code */
-  uint16_t aa; /* Authoritative Answer Flag */
-  uint16_t tc; /* Truncation Flag */
-  uint16_t rd; /* Recursion Desired */
-  uint16_t ra; /* Recursion Available */
-  uint16_t rcode; /* Response Code */
-
-  uint16_t qdCount; /* Question Count */
-  uint16_t anCount; /* Answer Record Count */
-  uint16_t nsCount; /* Authority Record Count */
-  uint16_t arCount; /* Additional Record Count */
-
-  /* At least one question; questions are copied to the response 1:1 */
-  struct Question* questions;
-
-  /*
-  * Resource records to be send back.
-  * Every resource record can be in any of the following places.
-  * But every place has a different semantic.
-  */
-  struct ResourceRecord* answers;
-  struct ResourceRecord* authorities;
-  struct ResourceRecord* additionals;
-};
-
-int get_A_Record(uint8_t addr[4], const char domain_name[])
-{
-  if (strcmp("foo.bar.com", domain_name) == 0)
-  {
-    addr[0] = 192;
-    addr[1] = 168;
-    addr[2] = 1;
-    addr[3] = 1;
-    return 0;
-  }
-  else
-  {
-    return -1;
-  }
-}
-
-int get_AAAA_Record(uint8_t addr[16], const char domain_name[])
-{
-  if (strcmp("foo.bar.com", domain_name) == 0)
-  {
-    addr[0] = 0xfe;
-    addr[1] = 0x80;
-    addr[2] = 0x00;
-    addr[3] = 0x00;
-    addr[4] = 0x00;
-    addr[5] = 0x00;
-    addr[6] = 0x00;
-    addr[7] = 0x00;
-    addr[8] = 0x00;
-    addr[9] = 0x00;
-    addr[10] = 0x00;
-    addr[11] = 0x00;
-    addr[12] = 0x00;
-    addr[13] = 0x00;
-    addr[14] = 0x00;
-    addr[15] = 0x01;
-    return 0;
-  }
-  else
-  {
-    return -1;
-  }
-}
-
-
-/*
-* Debugging functions.
-*/
-
-void print_hex(uint8_t* buf, size_t len)
-{
-  int i;
-  printf("%zu bytes:\n", len);
-  for(i = 0; i < len; ++i)
-    printf("%02x ", buf[i]);
-  printf("\n");
-}
-
-void print_resource_record(struct ResourceRecord* rr)
-{
-  int i;
-  while (rr)
-  {
-    printf("  ResourceRecord { name '%s', type %u, class %u, ttl %u, rd_length %u, ",
-        rr->name,
-        rr->type,
-        rr->class,
-        rr->ttl,
-        rr->rd_length
-   );
-
-    union ResourceData *rd = &rr->rd_data;
-    switch (rr->type)
-    {
-      case A_Resource_RecordType:
-        printf("Address Resource Record { address ");
-
-        for(i = 0; i < 4; ++i)
-          printf("%s%u", (i ? "." : ""), rd->a_record.addr[i]);
-
-        printf(" }");
-        break;
-      case NS_Resource_RecordType:
-        printf("Name Server Resource Record { name %s }",
-          rd->name_server_record.name
-       );
-        break;
-      case CNAME_Resource_RecordType:
-        printf("Canonical Name Resource Record { name %u }",
-          rd->cname_record.name
-       );
-        break;
-      case SOA_Resource_RecordType:
-        printf("SOA { MName '%s', RName '%s', serial %u, refresh %u, retry %u, expire %u, minimum %u }",
-          rd->soa_record.MName,
-          rd->soa_record.RName,
-          rd->soa_record.serial,
-          rd->soa_record.refresh,
-          rd->soa_record.retry,
-          rd->soa_record.expire,
-          rd->soa_record.minimum
-       );
-        break;
-      case PTR_Resource_RecordType:
-        printf("Pointer Resource Record { name '%s' }",
-          rd->ptr_record.name
-       );
-        break;
-      case MX_Resource_RecordType:
-        printf("Mail Exchange Record { preference %u, exchange '%s' }",
-          rd->mx_record.preference,
-          rd->mx_record.exchange
-       );
-        break;
-      case TXT_Resource_RecordType:
-        printf("Text Resource Record { txt_data '%s' }",
-          rd->txt_record.txt_data
-       );
-        break;
-      case AAAA_Resource_RecordType:
-        printf("AAAA Resource Record { address ");
-
-        for(i = 0; i < 16; ++i)
-          printf("%s%02x", (i ? ":" : ""), rd->aaaa_record.addr[i]);
-
-        printf(" }");
-        break;
-      default:
-        printf("Unknown Resource Record { ??? }");
-    }
-    printf("}\n");
-    rr = rr->next;
-  }
-}
-
-void print_query(struct Message* msg)
-{
-  printf("QUERY { ID: %02x", msg->id);
-  printf(". FIELDS: [ QR: %u, OpCode: %u ]", msg->qr, msg->opcode);
-  printf(", QDcount: %u", msg->qdCount);
-  printf(", ANcount: %u", msg->anCount);
-  printf(", NScount: %u", msg->nsCount);
-  printf(", ARcount: %u,\n", msg->arCount);
-
-  struct Question* q = msg->questions;
-  while (q)
-  {
-    printf("  Question { qName '%s', qType %u, qClass %u }\n",
-      q->qName,
-      q->qType,
-      q->qClass
-   );
-    q = q->next;
-  }
-
-  print_resource_record(msg->answers);
-  print_resource_record(msg->authorities);
-  print_resource_record(msg->additionals);
-
-  printf("}\n");
-}
-
-
-/*
-* Basic memory operations.
-*/
-
-size_t get16bits(const uint8_t** buffer)
-{
-  uint16_t value;
-
-  memcpy(&value, *buffer, 2);
-  *buffer += 2;
-
-  return ntohs(value);
-}
-
-void put8bits(uint8_t** buffer, uint8_t value)
-{
-  memcpy(*buffer, &value, 1);
-  *buffer += 1;
-}
-
-void put16bits(uint8_t** buffer, uint16_t value)
-{
-  value = htons(value);
-  memcpy(*buffer, &value, 2);
-  *buffer += 2;
-}
-
-void put32bits(uint8_t** buffer, uint32_t value)
-{
-  value = htons(value);
-  memcpy(*buffer, &value, 4);
-  *buffer += 4;
-}
-
-
-/*
-* Deconding/Encoding functions.
-*/
-
-// 3foo3bar3com0 => foo.bar.com
-char* decode_domain_name(const uint8_t** buffer)
-{
-  char name[256];
-  const uint8_t* buf = *buffer;
-  int j = 0;
-  int i = 0;
-
-  while (buf[i] != 0)
-  {
-    //if (i >= buflen || i > sizeof(name))
-    //  return NULL;
-
-    if (i != 0)
-    {
-      name[j] = '.';
-      j += 1;
-    }
-
-    int len = buf[i];
-    i += 1;
-
-    memcpy(name+j, buf+i, len);
-    i += len;
-    j += len;
-  }
-
-  name[j] = '\0';
-
-  *buffer += i + 1; //also jump over the last 0
-
-  return strdup(name);
-}
-
-// foo.bar.com => 3foo3bar3com0
-void encode_domain_name(uint8_t** buffer, const char* domain)
-{
-  uint8_t* buf = *buffer;
-  const char* beg = domain;
-  const char* pos;
-  int len = 0;
-  int i = 0;
-
-  while ((pos = strchr(beg, '.')))
-  {
-    len = pos - beg;
-    buf[i] = len;
-    i += 1;
-    memcpy(buf+i, beg, len);
-    i += len;
-
-    beg = pos + 1;
-  }
-
-  len = strlen(domain) - (beg - domain);
-
-  buf[i] = len;
-  i += 1;
-
-  memcpy(buf + i, beg, len);
-  i += len;
-
-  buf[i] = 0;
-  i += 1;
-
-  *buffer += i;
-}
-
-
-void decode_header(struct Message* msg, const uint8_t** buffer)
-{
-  msg->id = get16bits(buffer);
-
-  uint32_t fields = get16bits(buffer);
-  msg->qr = (fields & QR_MASK) >> 15;
-  msg->opcode = (fields & OPCODE_MASK) >> 11;
-  msg->aa = (fields & AA_MASK) >> 10;
-  msg->tc = (fields & TC_MASK) >> 9;
-  msg->rd = (fields & RD_MASK) >> 8;
-  msg->ra = (fields & RA_MASK) >> 7;
-  msg->rcode = (fields & RCODE_MASK) >> 0;
-
-  msg->qdCount = get16bits(buffer);
-  msg->anCount = get16bits(buffer);
-  msg->nsCount = get16bits(buffer);
-  msg->arCount = get16bits(buffer);
-}
-
-void encode_header(struct Message* msg, uint8_t** buffer)
-{
-  put16bits(buffer, msg->id);
-
-  int fields = 0;
-  fields |= (msg->qr << 15) & QR_MASK;
-  fields |= (msg->rcode << 0) & RCODE_MASK;
-  // TODO: insert the rest of the fields
-  put16bits(buffer, fields);
-
-  put16bits(buffer, msg->qdCount);
-  put16bits(buffer, msg->anCount);
-  put16bits(buffer, msg->nsCount);
-  put16bits(buffer, msg->arCount);
-}
-
-int decode_msg(struct Message* msg, const uint8_t* buffer, int size)
-{
-  int i;
-
-  decode_header(msg, &buffer);
-
-  if (msg->anCount != 0 || msg->nsCount != 0)
-  {
-    printf("Only questions expected!\n");
-    return -1;
-  }
-
-  // parse questions
-  uint32_t qcount = msg->qdCount;
-  struct Question* qs = msg->questions;
-  for (i = 0; i < qcount; ++i)
-  {
-    struct Question* q = malloc(sizeof(struct Question));
-
-    q->qName = decode_domain_name(&buffer);
-    q->qType = get16bits(&buffer);
-    q->qClass = get16bits(&buffer);
-
-    // prepend question to questions list
-    q->next = qs;
-    msg->questions = q;
-  }
-
-  // We do not expect any resource records to parse here.
-
-  return 0;
-}
-
-// For every question in the message add a appropiate resource record
-// in either section 'answers', 'authorities' or 'additionals'.
-void resolver_process(struct Message* msg)
-{
-  struct ResourceRecord* beg;
-  struct ResourceRecord* rr;
-  struct Question* q;
-  int rc;
-
-  // leave most values intact for response
-  msg->qr = 1; // this is a response
-  msg->aa = 1; // this server is authoritative
-  msg->ra = 0; // no recursion available
-  msg->rcode = Ok_ResponseType;
-
-  // should already be 0
-  msg->anCount = 0;
-  msg->nsCount = 0;
-  msg->arCount = 0;
-
-  // for every question append resource records
-  q = msg->questions;
-  while (q)
-  {
-    rr = malloc(sizeof(struct ResourceRecord));
-    memset(rr, 0, sizeof(struct ResourceRecord));
-
-    rr->name = strdup(q->qName);
-    rr->type = q->qType;
-    rr->class = q->qClass;
-    rr->ttl = 60*60; // in seconds; 0 means no caching
-
-    printf("Query for '%s'\n", q->qName);
-
-    // We only can only answer two question types so far
-    // and the answer (resource records) will be all put
-    // into the answers list.
-    // This behavior is probably non-standard!
-    switch (q->qType)
-    {
-      case A_Resource_RecordType:
-        rr->rd_length = 4;
-        rc = get_A_Record(rr->rd_data.a_record.addr, q->qName);
-        if (rc < 0)
-        {
-          free(rr->name);
-          free(rr);
-          goto next;
-        }
-        break;
-      case AAAA_Resource_RecordType:
-        rr->rd_length = 16;
-        rc = get_AAAA_Record(rr->rd_data.aaaa_record.addr, q->qName);
-        if (rc < 0)
-        {
-          free(rr->name);
-          free(rr);
-          goto next;
-        }
-        break;
-      /*
-      case NS_Resource_RecordType:
-      case CNAME_Resource_RecordType:
-      case SOA_Resource_RecordType:
-      case PTR_Resource_RecordType:
-      case MX_Resource_RecordType:
-      case TXT_Resource_RecordType:
-      */
-      default:
-        free(rr);
-        msg->rcode = NotImplemented_ResponseType;
-        printf("Cannot answer question of type %d.\n", q->qType);
-        goto next;
-    }
-
-    msg->anCount++;
-
-    // prepend resource record to answers list
-    beg = msg->answers;
-    msg->answers = rr;
-    rr->next = beg;
-
-    // jump here to omit question
-    next:
-
-    // process next question
-    q = q->next;
-  }
-}
-
-/* @return 0 upon failure, 1 upon success */
-int encode_resource_records(struct ResourceRecord* rr, uint8_t** buffer)
-{
-  int i;
-  while (rr)
-  {
-    // Answer questions by attaching resource sections.
-    encode_domain_name(buffer, rr->name);
-    put16bits(buffer, rr->type);
-    put16bits(buffer, rr->class);
-    put32bits(buffer, rr->ttl);
-    put16bits(buffer, rr->rd_length);
-
-    switch (rr->type)
-    {
-      case A_Resource_RecordType:
-        for(i = 0; i < 4; ++i)
-          put8bits(buffer, rr->rd_data.a_record.addr[i]);
-        break;
-      case AAAA_Resource_RecordType:
-        for(i = 0; i < 16; ++i)
-          put8bits(buffer, rr->rd_data.aaaa_record.addr[i]);
-        break;
-      default:
-        fprintf(stderr, "Unknown type %u. => Ignore resource record.\n", rr->type);
-      return 1;
-    }
-
-    rr = rr->next;
-  }
-
-  return 0;
-}
-
-/* @return 0 upon failure, 1 upon success */
-int encode_msg(struct Message* msg, uint8_t** buffer)
-{
-  struct Question* q;
-  int rc;
-
-  encode_header(msg, buffer);
-
-  q = msg->questions;
-  while (q)
-  {
-    encode_domain_name(buffer, q->qName);
-    put16bits(buffer, q->qType);
-    put16bits(buffer, q->qClass);
-
-    q = q->next;
-  }
-
-  rc = 0;
-  rc |= encode_resource_records(msg->answers, buffer);
-  rc |= encode_resource_records(msg->authorities, buffer);
-  rc |= encode_resource_records(msg->additionals, buffer);
-
-  return rc;
-}
-
-void free_resource_records(struct ResourceRecord* rr)
-{
-  struct ResourceRecord* next;
-
-  while (rr) {
-    free(rr->name);
-    next = rr->next;
-    free(rr);
-    rr = next;
-  }
-}
-
-void free_questions(struct Question* qq)
-{
-  struct Question* next;
-
-  while (qq) {
-    free(qq->qName);
-    next = qq->next;
-    free(qq);
-    qq = next;
-  }
-}
-
-int main()
-{
-  // buffer for input/output binary packet
-  uint8_t buffer[BUF_SIZE];
-  struct sockaddr_in client_addr;
-  socklen_t addr_len = sizeof(struct sockaddr_in);
-  struct sockaddr_in addr;
-  int nbytes, rc;
-  int sock;
-  int port = 53;
-
-  struct Message msg;
-  memset(&msg, 0, sizeof(struct Message));
-
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons(port);
-
-  sock = socket(AF_INET, SOCK_DGRAM, 0);
-
-  rc = bind(sock, (struct sockaddr*) &addr, addr_len);
-
-  if (rc != 0)
-  {
-    printf("Could not bind: %s\n", strerror(errno));
-    return 1;
-  }
-
-  printf("Listening on port %u.\n", port);
-
-  while (1)
-  {
-    free_questions(msg.questions);
-    free_resource_records(msg.answers);
-    free_resource_records(msg.authorities);
-    free_resource_records(msg.additionals);
-    memset(&msg, 0, sizeof(struct Message));
-
-    nbytes = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &client_addr, &addr_len);
-
-    if (decode_msg(&msg, buffer, nbytes) != 0) {
-      continue;
-    }
-
-    /* Print query */
-    print_query(&msg);
-
-    resolver_process(&msg);
-
-    /* Print response */
-    print_query(&msg);
-
-    uint8_t *p = buffer;
-    if (encode_msg(&msg, &p) != 0) {
-      continue;
-    }
-
-    int buflen = p - buffer;
-    sendto(sock, buffer, buflen, 0, (struct sockaddr*) &client_addr, addr_len);
-  }
-}