Add systemd script
This commit is contained in:
5
etc/default/smartdns
Normal file
5
etc/default/smartdns
Normal 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
77
etc/init.d/smartdns
Normal 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
|
||||||
|
|
||||||
@@ -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
204
install
Normal 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
2
Makefile → src/Makefile
Executable file → Normal 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
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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();
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
6
fast_ping.c → src/fast_ping.c
Executable file → Normal 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
6
fast_ping.h → src/fast_ping.h
Executable file → Normal 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
0
include/atomic.h → src/include/atomic.h
Executable file → Normal file
116
smartdns.c → src/smartdns.c
Executable file → Normal file
116
smartdns.c → src/smartdns.c
Executable file → Normal 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|
||||||
@@ -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
14
systemd/smartdns.service
Normal 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
|
||||||
755
test-dns.c
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user