From 7e60b9bc72039ab7e6d702bc8e6254a623e94d9c Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Mon, 25 Jun 2018 00:03:24 +0800 Subject: [PATCH] Add address rule --- etc/smartdns/smartdns.conf | 8 +++- src/conf.c | 87 +++++++++++++++++++++++++++++++++++--- src/conf.h | 17 ++++++++ src/dns_server.c | 62 +++++++++++++++++++++++++++ src/smartdns.c | 1 - src/tlog.c | 10 +++-- src/util.c | 33 +++++++++++++++ src/util.h | 2 + 8 files changed, 207 insertions(+), 13 deletions(-) diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index 28a55a8..b8533ea 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -4,7 +4,7 @@ # IPV4: :53 # IPV6 [::]:53 -bind :53 +bind [::]:53 # dns cache size # cache-size [number] @@ -42,3 +42,9 @@ server 202.141.162.123:53 # remote tcp dns server list # server-tcp [IP]:[PORT], default port is 53 # server-tcp 114.114.114.114 + +# specific address to domain +# address /domain/ip +# address /www.example.com/1.2.3.4 +address /cnzz.com/127.0.0.1 +address /adsame.com/127.0.0.1 \ No newline at end of file diff --git a/src/conf.c b/src/conf.c index a901ab6..53682e9 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1,5 +1,7 @@ #include "conf.h" #include "tlog.h" +#include "list.h" +#include "rbtree.h" #include "util.h" #include #include @@ -16,6 +18,7 @@ int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE; struct dns_servers dns_conf_servers[DNS_MAX_SERVERS]; int dns_conf_server_num; int dns_conf_loglevel = TLOG_ERROR; +LIST_HEAD(dns_conf_address_list); int config_bind(char *value) { @@ -38,15 +41,15 @@ int config_server(char *value, dns_conf_server_type_t type) server = &dns_conf_servers[index]; /* parse ip, port from value */ - if (parse_ip(value, server->server, &port) != 0) { + if (parse_ip(value, server->server, &port) != 0) { return -1; - } + } /* if port is not defined, set port to default 53 */ if (port == PORT_NOT_DEFINED) { - port= DEFAULT_DNS_PORT; - } - + port = DEFAULT_DNS_PORT; + } + server->type = type; server->port = port; dns_conf_server_num++; @@ -54,6 +57,75 @@ int config_server(char *value, dns_conf_server_type_t type) return 0; } +int config_address(char *value) +{ + struct dns_address *address; + char ip[MAX_IP_LEN]; + char *begin = NULL; + char *end = NULL; + int len = 0; + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + + begin = strstr(value, "/"); + if (begin == NULL) { + goto errout; + } + + begin++; + end = strstr(begin, "/"); + if (end == NULL) { + goto errout; + } + + address = malloc(sizeof(*address)); + if (address == NULL) { + goto errout; + } + + len = end - begin; + memcpy(address->domain, begin, len); + address->domain[len] = 0; + strncpy(ip, end + 1, MAX_IP_LEN); + + if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) { + goto errout; + } + + switch (addr.ss_family) { + case AF_INET: { + struct sockaddr_in *addr_in; + addr_in = (struct sockaddr_in *)&addr; + memcpy(address->ipv4_addr, &addr_in->sin_addr.s_addr, 4); + address->addr_type = DNS_T_A; + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6; + addr_in6 = (struct sockaddr_in6 *)&addr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { + memcpy(address->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4); + address->addr_type = DNS_T_A; + } else { + memcpy(address->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16); + address->addr_type = DNS_T_AAAA; + } + } break; + default: + goto errout; + } + + list_add_tail(&address->list, &dns_conf_address_list); + + return 0; +errout: + if (address) { + free(address); + } + + tlog(TLOG_ERROR, "add address %s failed", value); + return 0; +} + int config_server_udp(char *value) { return config_server(value, DNS_CONF_TYPE_UDP); @@ -106,8 +178,9 @@ struct config_item { struct config_item config_item[] = { {"bind", config_bind}, {"server", config_server_udp}, - {"server-tcp", config_server_tcp}, - {"server-http", config_server_http}, + {"address", config_address}, + {"server-tcp", config_server_tcp}, + {"server-http", config_server_http}, {"cache-size", config_cache_size}, {"loglevel", config_log_level}, }; diff --git a/src/conf.h b/src/conf.h index 0421ae3..89cc916 100644 --- a/src/conf.h +++ b/src/conf.h @@ -1,9 +1,14 @@ #ifndef _DNS_CONF +#define _DNS_CONF + +#include "list.h" +#include "dns.h" #define DNS_MAX_SERVERS 32 #define DNS_MAX_IPLEN 64 #define DNS_MAX_PATH 1024 #define DEFAULT_DNS_PORT 53 +#define DNS_MAX_CONF_CNAME_LEN 128 typedef enum dns_conf_server_type { DNS_CONF_TYPE_UDP, @@ -17,6 +22,17 @@ struct dns_servers { dns_conf_server_type_t type; }; +struct dns_address { + struct list_head list; + char domain[DNS_MAX_CONF_CNAME_LEN]; + dns_type_t addr_type; + union { + unsigned char ipv4_addr[DNS_RR_A_LEN]; + unsigned char ipv6_addr[DNS_RR_AAAA_LEN]; + unsigned char addr[0]; + }; +}; + extern char dns_conf_server_ip[DNS_MAX_IPLEN]; extern int dns_conf_cachesize; extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS]; @@ -25,6 +41,7 @@ extern int dns_conf_verbose; extern int dns_conf_loglevel; extern char dns_conf_logfile[DNS_MAX_PATH]; extern int dns_conf_lognum; +extern struct list_head dns_conf_address_list; int load_conf(const char *file); diff --git a/src/dns_server.c b/src/dns_server.c index 75c71f7..4bc2d4e 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -669,6 +669,63 @@ errout: return -1; } +static struct dns_address *_dns_server_get_address_by_domain(char *domain) +{ + struct dns_address *address; + char *match = NULL; + int domain_len; + + list_for_each_entry(address, &dns_conf_address_list, list) + { + domain_len = strnlen(address->domain, DNS_MAX_CNAME_LEN); + match = strstr(domain, address->domain); + if (match) { + if (memcmp(address->domain, match, domain_len + 1) == 0) { + return address; + } + } + } + + return NULL; +} + +static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet) +{ + struct dns_address *address = NULL; + + address = _dns_server_get_address_by_domain(request->domain); + if (address == NULL) { + goto errout; + } + + if (request->qtype != address->addr_type) { + goto errout; + } + + switch (request->qtype) { + case DNS_T_A: + memcpy(request->ipv4_addr, address->ipv4_addr, DNS_RR_A_LEN); + request->ttl_v4 = 600; + request->has_ipv4 = 1; + break; + case DNS_T_AAAA: + memcpy(request->ipv6_addr, address->ipv6_addr, DNS_RR_AAAA_LEN); + request->ttl_v6 = 600; + request->has_ipv6 = 1; + break; + default: + goto errout; + break; + } + + request->rcode = DNS_RC_NOERROR; + _dns_reply(request); + + return 0; +errout: + return -1; +} + static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr_storage *from, socklen_t from_len) { int decode_len; @@ -746,6 +803,11 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so break; } + if (_dns_server_process_address(request, packet) == 0) { + free(request); + return 0; + } + tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, gethost_by_addr(name, (struct sockaddr *)from, from_len), qtype); _dns_server_request_get(request); diff --git a/src/smartdns.c b/src/smartdns.c index 3d03266..8c23591 100644 --- a/src/smartdns.c +++ b/src/smartdns.c @@ -234,7 +234,6 @@ void smartdns_exit(void) void sig_handle(int sig) { - switch (sig) { case SIGINT: dns_server_stop(); diff --git a/src/tlog.c b/src/tlog.c index fd3ecd6..98cdb67 100644 --- a/src/tlog.c +++ b/src/tlog.c @@ -252,8 +252,8 @@ static int _tlog_log_buffer(char *buff, int maxlen, tlog_level level, const char struct tlog_info info; if (tlog_format == NULL) { - return -1; - } + return -1; + } if (level >= TLOG_END) { return -1; @@ -288,8 +288,10 @@ int tlog_vext(tlog_level level, const char *file, int line, const char *func, vo int maxlen = 0; if (tlog.buff == NULL) { - return -1; - } + vprintf(format, ap); + printf("\n"); + return -1; + } if (level < tlog_set_level) { return 0; diff --git a/src/util.c b/src/util.c index 68c1c84..6702a8b 100644 --- a/src/util.c +++ b/src/util.c @@ -47,6 +47,39 @@ errout: return NULL; } +int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len) +{ + struct addrinfo hints; + struct addrinfo *result = NULL; + int ret = 0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo(host, "53", &hints, &result); + if (ret != 0) { + goto errout; + } + + if (result->ai_addrlen > *addr_len) { + result->ai_addrlen = *addr_len; + } + + memcpy(addr, result->ai_addr, result->ai_addrlen); + *addr_len = result->ai_addrlen; + + freeaddrinfo(result); + + return 0; +errout: + if (result) { + freeaddrinfo(result); + } + return -1; + +} + int parse_ip(const char *value, char *ip, int *port) { int offset = 0; diff --git a/src/util.h b/src/util.h index 72c417e..9c99bbd 100644 --- a/src/util.h +++ b/src/util.h @@ -12,6 +12,8 @@ unsigned long get_tick_count(void); char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len); +int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len); + int parse_ip(const char *value, char *ip, int *port); int set_fd_nonblock(int fd, int nonblock);