Add systemd script

This commit is contained in:
Nick Peng
2018-06-16 02:36:04 +08:00
parent 53df9f7063
commit 7b62739c13
34 changed files with 746 additions and 869 deletions

5
etc/default/smartdns Normal file
View File

@@ -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
etc/init.d/smartdns Normal file
View File

@@ -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

View File

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

204
install Normal file
View File

@@ -0,0 +1,204 @@
#!/bin/sh
#
# Copyright (C) 2018 Ruilin Peng (Nick) <pymumu@gmail.com>
#
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 $?

2
Makefile → src/Makefile Executable file → Normal file
View File

@@ -1,7 +1,7 @@
BIN=smartdns 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 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 +=-Iinclude
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\" CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
CXXFLAGS=-g -O0 -Wall -std=c++11 CXXFLAGS=-g -O0 -Wall -std=c++11

View File

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

View File

View File

@@ -18,8 +18,12 @@
#include "dns.h" #include "dns.h"
#include "tlog.h" #include "tlog.h"
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define QR_MASK 0x8000 #define QR_MASK 0x8000
#define OPCODE_MASK 0x7800 #define OPCODE_MASK 0x7800
@@ -28,25 +32,26 @@
#define RD_MASK 0x0100 #define RD_MASK 0x0100
#define RA_MASK 0x0080 #define RA_MASK 0x0080
#define RCODE_MASK 0x000F #define RCODE_MASK 0x000F
#define DNS_RR_END (0XFFFF) #define DNS_RR_END (0XFFFF)
/* read short and move pointer */
short dns_read_short(unsigned char **buffer) short dns_read_short(unsigned char **buffer)
{ {
unsigned short value; unsigned short value;
value = ntohs(*((unsigned short *)(*buffer))); value = ntohs(*((unsigned short *)(*buffer)));
*buffer += 2; *buffer += 2;
return value; return value;
} }
/* write char and move pointer */
void dns_write_char(unsigned char **buffer, unsigned char value) void dns_write_char(unsigned char **buffer, unsigned char value)
{ {
**buffer = value; **buffer = value;
*buffer += 1; *buffer += 1;
} }
/* read char and move pointer */
unsigned char dns_read_char(unsigned char **buffer) unsigned char dns_read_char(unsigned char **buffer)
{ {
unsigned char value = **buffer; unsigned char value = **buffer;
@@ -54,6 +59,7 @@ unsigned char dns_read_char(unsigned char **buffer)
return value; return value;
} }
/* write short and move pointer */
void dns_write_short(unsigned char **buffer, unsigned short value) void dns_write_short(unsigned char **buffer, unsigned short value)
{ {
value = htons(value); value = htons(value);
@@ -61,6 +67,7 @@ void dns_write_short(unsigned char **buffer, unsigned short value)
*buffer += 2; *buffer += 2;
} }
/* write int and move pointer */
void dns_write_int(unsigned char **buffer, unsigned int value) void dns_write_int(unsigned char **buffer, unsigned int value)
{ {
value = htonl(value); value = htonl(value);
@@ -68,6 +75,7 @@ void dns_write_int(unsigned char **buffer, unsigned int value)
*buffer += 4; *buffer += 4;
} }
/* read int and move pointer */
unsigned int dns_read_int(unsigned char **buffer) unsigned int dns_read_int(unsigned char **buffer)
{ {
unsigned int value; unsigned int value;
@@ -78,11 +86,13 @@ unsigned int dns_read_int(unsigned char **buffer)
return value; return value;
} }
/* iterator get rrs begin */
struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count) struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count)
{ {
unsigned short start; unsigned short start;
struct dns_head *head = &packet->head; struct dns_head *head = &packet->head;
/* get rrs count by rrs type */
switch (type) { switch (type) {
case DNS_RRS_QD: case DNS_RRS_QD:
*count = head->qdcount; *count = head->qdcount;
@@ -105,13 +115,16 @@ struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, i
break; break;
} }
/* if not resource record, reutrn null */
if (start == DNS_RR_END) { if (start == DNS_RR_END) {
return NULL; return NULL;
} }
/* return rrs data start address */
return (struct dns_rrs *)(packet->data + start); 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) struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs)
{ {
if (rrs->next == DNS_RR_END) { 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); return (struct dns_rrs *)(packet->data + rrs->next);
} }
/* iterator add rrs begin */
unsigned char *_dns_add_rrs_start(struct dns_packet *packet, int *maxlen) unsigned char *_dns_add_rrs_start(struct dns_packet *packet, int *maxlen)
{ {
struct dns_rrs *rrs; struct dns_rrs *rrs;
unsigned char *end = packet->data + packet->len; unsigned char *end = packet->data + packet->len;
rrs = (struct dns_rrs *)end; rrs = (struct dns_rrs *)end;
*maxlen = packet->size - packet->len - sizeof(*packet); *maxlen = packet->size - packet->len - sizeof(*packet);
if (packet->len >= packet->size - sizeof(*packet)) { if (packet->len >= packet->size - sizeof(*packet)) {
/* if size exceeds max packet size, return NULL */
return NULL; return NULL;
} }
return rrs->data; return rrs->data;
} }
/* iterator add rrs end */
int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int len) 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;
struct dns_rrs *rrs_next; struct dns_rrs *rrs_next;
struct dns_head *head = &packet->head; struct dns_head *head = &packet->head;
unsigned char *end = packet->data + packet->len; unsigned char *end = packet->data + packet->len;
rrs = (struct dns_rrs *)end;
unsigned short *count; unsigned short *count;
unsigned short *start; unsigned short *start;
rrs = (struct dns_rrs *)end;
if (packet->len + len > packet->size - sizeof(*packet)) { if (packet->len + len > packet->size - sizeof(*packet)) {
return -1; return -1;
} }
@@ -169,6 +186,7 @@ int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int le
break; break;
} }
/* add data to end of dns_packet, and set previouse rrs point to this rrs */
if (*start != DNS_RR_END) { if (*start != DNS_RR_END) {
rrs_next = (struct dns_rrs *)(packet->data + *start); rrs_next = (struct dns_rrs *)(packet->data + *start);
while (rrs_next->next != DNS_RR_END) { 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; *start = packet->len;
} }
rrs->next = DNS_RR_END; //*start; /* update rrs head info */
*count += 1;
rrs->len = len; rrs->len = len;
rrs->type = rtype; rrs->type = rtype;
rrs->next = DNS_RR_END;
/* update total data length */
*count += 1;
packet->len += len + sizeof(*rrs); packet->len += len + sizeof(*rrs);
return 0; return 0;
} }
static inline int _dns_data_left_len(struct dns_data_context *data_context) 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); 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) int _dns_add_qr_head(struct dns_data_context *data_context, char *domain, int qtype, int qclass)
{ {
/* question head */
/* |domain |
* |qtype | qclass |
*/
while (1) { while (1) {
if (_dns_data_left_len(data_context) < 1) { if (_dns_data_left_len(data_context) < 1) {
return -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 _dns_get_qr_head(struct dns_data_context *data_context, char *domain, int maxsize, int *qtype, int *qclass)
{ {
int i; int i;
/* question head */
/* |domain |
* |qtype | qclass |
*/
for (i = 0; i < maxsize; i++) { for (i = 0; i < maxsize; i++) {
if (_dns_data_left_len(data_context) < 1) { if (_dns_data_left_len(data_context) < 1) {
return -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; int len = 0;
/* resource record head */
/* |domain |
* |qtype | qclass |
* | ttl |
* | rrlen | rrdata |
*/
len = _dns_add_qr_head(data_context, domain, qtype, qclass); len = _dns_add_qr_head(data_context, domain, qtype, qclass);
if (len < 0) { if (len < 0) {
return -1; return -1;
@@ -279,6 +314,12 @@ int _dns_get_rr_head(struct dns_data_context *data_context, char *domain, int ma
{ {
int len = 0; int len = 0;
/* resource record head */
/* |domain |
* |qtype | qclass |
* | ttl |
* | rrlen | rrdata |
*/
len = _dns_get_qr_head(data_context, domain, maxsize, qtype, qclass); len = _dns_get_qr_head(data_context, domain, maxsize, qtype, qclass);
if (_dns_data_left_len(data_context) < 6) { 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; int len = 0;
struct dns_data_context data_context; struct dns_data_context data_context;
/* resource record */
/* |domain |
* |qtype | qclass |
* | ttl |
* | rrlen | rrdata |
*/
unsigned char *data = _dns_add_rrs_start(packet, &maxlen); unsigned char *data = _dns_add_rrs_start(packet, &maxlen);
if (data == NULL) { if (data == NULL) {
return -1; 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.ptr = data;
data_context.maxsize = maxlen; data_context.maxsize = maxlen;
/* add rr head */
len = _dns_add_rr_head(&data_context, domain, rtype, DNS_C_IN, ttl, raw_len); len = _dns_add_rr_head(&data_context, domain, rtype, DNS_C_IN, ttl, raw_len);
if (len < 0) { if (len < 0) {
return -1; return -1;
} }
/* add rr data */
memcpy(data_context.ptr, raw, raw_len); memcpy(data_context.ptr, raw, raw_len);
data_context.ptr += raw_len; data_context.ptr += raw_len;
len = data_context.ptr - data_context.data; 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; int ret = 0;
struct dns_data_context data_context; struct dns_data_context data_context;
/* resource record head */
/* |domain |
* |qtype | qclass |
* | ttl |
* | rrlen | rrdata |
*/
unsigned char *data = rrs->data; unsigned char *data = rrs->data;
data_context.data = data; data_context.data = data;
data_context.ptr = data; data_context.ptr = data;
data_context.maxsize = rrs->len; data_context.maxsize = rrs->len;
/* get rr head */
ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len);
if (ret < 0) { if (ret < 0) {
return -1; return -1;
@@ -348,6 +404,7 @@ int dns_get_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, void *
return -1; return -1;
} }
/* get rr data */
memcpy(raw, data_context.ptr, rr_len); memcpy(raw, data_context.ptr, rr_len);
data_context.ptr += rr_len; data_context.ptr += rr_len;
*raw_len = 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) 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 data[sizeof(*soa)];
unsigned char *ptr = data; unsigned char *ptr = data;
int len = 0; 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; unsigned char *ptr = data;
int len = sizeof(data); int len = sizeof(data);
/* SOA */
/*| mname |
*| rname |
*| serial |
*| refersh |
*| retry |
*| expire |
*| minimum |
*/
if (dns_get_RAW(rrs, domain, maxsize, ttl, data, &len) != 0) { if (dns_get_RAW(rrs, domain, maxsize, ttl, data, &len) != 0) {
return -1; return -1;
} }
@@ -531,6 +606,23 @@ static int _dns_decode_head(struct dns_context *context)
return -1; 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); head->id = dns_read_short(&context->ptr);
fields = dns_read_short(&context->ptr); fields = dns_read_short(&context->ptr);
head->qr = (fields & QR_MASK) >> 15; 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; unsigned char *ptr = context->ptr;
int is_compressed = 0; int is_compressed = 0;
/*[len]string[len]string...[0]0 */
while (1) { while (1) {
if (ptr > context->data + context->maxsize || ptr < context->data) { if (ptr > context->data + context->maxsize || ptr < context->data) {
return -1; return -1;
@@ -595,35 +688,45 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
break; break;
} }
/* compressed domain */
if (len >= 0xC0) { 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; len = dns_read_short(&ptr) & 0x3FFF;
if (is_compressed == 0) { if (is_compressed == 0) {
context->ptr = ptr; context->ptr = ptr;
} }
ptr = context->data + len; ptr = context->data + len;
if (context->maxsize - (ptr - context->data) < 0) { 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; return -1;
} }
is_compressed = 1; is_compressed = 1;
continue; continue;
} }
/* change [len] to '.' */
if (output_len > 0) { if (output_len > 0) {
*output = '.'; *output = '.';
output++; output++;
} }
if (context->maxsize - (ptr - context->data) < 0) { 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; return -1;
} }
ptr++; ptr++;
if (output_len < size - 1) { if (output_len < size - 1) {
/* copy sub string */
copy_len = (len < size - output_len) ? len : size - 1 - output_len; copy_len = (len < size - output_len) ? len : size - 1 - output_len;
if (context->maxsize - (ptr - context->data) < 0) { 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; return -1;
} }
memcpy(output, ptr, copy_len); memcpy(output, ptr, copy_len);
@@ -647,6 +750,7 @@ static int _dns_encode_domain(struct dns_context *context, char *domain)
int total_len = 0; int total_len = 0;
unsigned char *ptr_num = context->ptr++; unsigned char *ptr_num = context->ptr++;
/*[len]string[len]string...[0]0 */
while (_dns_left_len(context) > 1 && *domain != 0) { while (_dns_left_len(context) > 1 && *domain != 0) {
if (*domain == '.') { if (*domain == '.') {
*ptr_num = num; *ptr_num = num;
@@ -665,6 +769,7 @@ static int _dns_encode_domain(struct dns_context *context, char *domain)
*ptr_num = num; *ptr_num = num;
if (total_len > 0) { if (total_len > 0) {
/* if domain is '\0', [domain] is '\0' */
*(context->ptr) = 0; *(context->ptr) = 0;
context->ptr++; 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) static int _dns_decode_qr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass)
{ {
int ret = 0; 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); ret = _dns_decode_domain(context, domain, domain_size);
if (ret < 0) { if (ret < 0) {
tlog(TLOG_ERROR, "decode domain failed."); 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]; char domain[DNS_MAX_CNAME_LEN];
int rr_len; int rr_len;
struct dns_data_context data_context; 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.data = rrs->data;
data_context.ptr = 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; struct dns_packet *packet = context->packet;
unsigned char *start; unsigned char *start;
/* decode rr head */
ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
if (ret < 0) { if (ret < 0) {
tlog(TLOG_ERROR, "decode head failed."); 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; start = context->ptr;
/* decode answer */
switch (qtype) { switch (qtype) {
case DNS_T_A: { case DNS_T_A: {
unsigned char addr[DNS_RR_A_LEN]; 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) { 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; return -1;
} }
@@ -1297,3 +1437,35 @@ int dns_encode(unsigned char *data, int size, struct dns_packet *packet)
return context.ptr - context.data; 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);
}

View File

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

View File

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

View File

@@ -18,16 +18,18 @@ typedef enum dns_result_type {
int dns_client_init(void); 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); 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(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); void dns_client_exit(void);
/* add remote dns server */
int dns_add_server(char *server_ip, int port, dns_server_type_t server_type); 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); int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type);
#endif #endif

View File

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

6
fast_ping.c → src/fast_ping.c Executable file → Normal file
View File

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

6
fast_ping.h → src/fast_ping.h Executable file → Normal file
View File

@@ -23,13 +23,15 @@ typedef enum {
struct ping_host_struct; 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); 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); 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_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 #ifdef __cpluscplus
} }

0
include/atomic.h → src/include/atomic.h Executable file → Normal file
View File

116
smartdns.c → src/smartdns.c Executable file → Normal file
View File

@@ -26,14 +26,36 @@
#include "tlog.h" #include "tlog.h"
#include "util.h" #include "util.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#define RESOLVE_FILE "/etc/resolv.conf" #define RESOLVE_FILE "/etc/resolv.conf"
#define MAX_LINE_LEN 1024 #define MAX_LINE_LEN 1024
#define MAX_KEY_LEN 64 #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) int smartdns_load_from_resolv(void)
{ {
@@ -101,15 +123,56 @@ int smartdns_add_servers(void)
return 0; return 0;
} }
int smartdns_init() int create_pid_file(const char *pid_file)
{
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;
}
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;
}
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; int ret;
if (load_conf("smartdns.conf") != 0) { ret = tlog_init(SMARTDNS_LOG_PATH, SMARTDNS_LOG_FILE, 1024 * 1024, 8, 1, 0, 0);
fprintf(stderr, "load config failed.");
}
ret = tlog_init(".", "smartdns.log", 1024 * 1024, 8, 1, 0, 0);
if (ret != 0) { if (ret != 0) {
tlog(TLOG_ERROR, "start tlog failed.\n"); tlog(TLOG_ERROR, "start tlog failed.\n");
goto errout; goto errout;
@@ -154,12 +217,12 @@ errout:
return -1; return -1;
} }
int smartdns_run() int smartdns_run(void)
{ {
return dns_server_run(); return dns_server_run();
} }
void smartdns_exit() void smartdns_exit(void)
{ {
dns_server_exit(); dns_server_exit();
dns_client_exit(); dns_client_exit();
@@ -185,11 +248,46 @@ void sig_handle(int sig)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret; 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); 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(); ret = smartdns_init();
if (ret != 0) { if (ret != 0) {
usleep(100000);
goto errout; goto errout;
} }

View File

View File

View File

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

View File

@@ -8,7 +8,7 @@
#define PORT_NOT_DEFINED -1 #define PORT_NOT_DEFINED -1
#define MAX_IP_LEN 64 #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); char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len);

14
systemd/smartdns.service Normal file
View File

@@ -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

View File

@@ -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);
}
}