Optimize configuration, and add blacklist ip features
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
BIN=smartdns
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o conf.o dns_cache.o $(OBJS_LIB)
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o $(OBJS_LIB)
|
||||
CFLAGS +=-O2 -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
||||
CFLAGS +=-Iinclude
|
||||
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
||||
|
||||
738
src/conf.c
738
src/conf.c
@@ -1,738 +0,0 @@
|
||||
#include "conf.h"
|
||||
#include "list.h"
|
||||
#include "rbtree.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_LINE_LEN 1024
|
||||
#define MAX_KEY_LEN 64
|
||||
|
||||
#define DEFAULT_DNS_CACHE_SIZE 512
|
||||
|
||||
char dns_conf_server_ip[DNS_MAX_IPLEN];
|
||||
char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
||||
int dns_conf_tcp_idle_time = 120;
|
||||
int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
struct dns_bogus_nxdomain dns_conf_bogus_nxdomain;
|
||||
char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
|
||||
int dns_conf_server_num;
|
||||
int dns_conf_log_level = TLOG_ERROR;
|
||||
char dns_conf_log_file[DNS_MAX_PATH];
|
||||
int dns_conf_log_size = 1024 * 1024;
|
||||
int dns_conf_log_num = 8;
|
||||
int dns_conf_audit_enable = 0;
|
||||
char dns_conf_audit_file[DNS_MAX_PATH];
|
||||
int dns_conf_audit_size = 1024 * 1024;
|
||||
int dns_conf_audit_num = 2;
|
||||
|
||||
art_tree dns_conf_domain_rule;
|
||||
radix_tree_t *dns_conf_address_rule;
|
||||
|
||||
int dns_conf_rr_ttl;
|
||||
int dns_conf_rr_ttl_min;
|
||||
int dns_conf_rr_ttl_max;
|
||||
int dns_conf_force_AAAA_SOA;
|
||||
|
||||
int load_conf_file(const char *file);
|
||||
|
||||
int config_bind(char *value)
|
||||
{
|
||||
/* server bind address */
|
||||
strncpy(dns_conf_server_ip, value, DNS_MAX_IPLEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_bind_tcp(char *value)
|
||||
{
|
||||
/* server bind address */
|
||||
strncpy(dns_conf_server_tcp_ip, value, DNS_MAX_IPLEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_server_name(char *value)
|
||||
{
|
||||
strncpy(dns_conf_server_name, value, DNS_MAX_CONF_CNAME_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_server(char *value, dns_server_type_t type, int default_port)
|
||||
{
|
||||
int index = dns_conf_server_num;
|
||||
struct dns_servers *server;
|
||||
int port = -1;
|
||||
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_ERROR, "exceeds max server number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
server = &dns_conf_servers[index];
|
||||
/* parse ip, port from value */
|
||||
if (parse_ip(value, server->server, &port) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if port is not defined, set port to default 53 */
|
||||
if (port == PORT_NOT_DEFINED) {
|
||||
port = default_port;
|
||||
}
|
||||
|
||||
server->type = type;
|
||||
server->port = port;
|
||||
dns_conf_server_num++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_domain_iter_cb(void *data, const unsigned char *key, uint32_t key_len, void *value)
|
||||
{
|
||||
free(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_domain_destroy(void)
|
||||
{
|
||||
art_iter(&dns_conf_domain_rule, config_domain_iter_cb, 0);
|
||||
art_tree_destroy(&dns_conf_domain_rule);
|
||||
}
|
||||
|
||||
void config_address_destroy(radix_node_t *node, void *cbctx)
|
||||
{
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(node->data);
|
||||
node->data = NULL;
|
||||
}
|
||||
|
||||
int config_address(char *value)
|
||||
{
|
||||
struct dns_address *address = NULL;
|
||||
struct dns_address *oldaddress;
|
||||
char ip[MAX_IP_LEN];
|
||||
char domain_key[DNS_MAX_CONF_CNAME_LEN];
|
||||
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||
char *begin = NULL;
|
||||
char *end = NULL;
|
||||
int len = 0;
|
||||
int port;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
char type = '4';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* remove prefix . */
|
||||
while (*begin == '.') {
|
||||
begin++;
|
||||
}
|
||||
|
||||
memset(address, 0, sizeof(*address));
|
||||
len = end - begin;
|
||||
memcpy(domain + 1, begin, len);
|
||||
|
||||
/* add dot for subdomain */
|
||||
domain[0] = '.';
|
||||
len++;
|
||||
|
||||
domain[len] = 0;
|
||||
reverse_string(domain_key + 1, domain, len);
|
||||
|
||||
if (parse_ip(end + 1, ip, &port) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
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;
|
||||
type = '4';
|
||||
} 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;
|
||||
type = '4';
|
||||
} else {
|
||||
memcpy(address->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
address->addr_type = DNS_T_AAAA;
|
||||
type = '6';
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
|
||||
domain_key[0] = type;
|
||||
len++;
|
||||
oldaddress = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, address);
|
||||
if (oldaddress) {
|
||||
free(oldaddress);
|
||||
}
|
||||
|
||||
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_SERVER_UDP, DEFAULT_DNS_PORT);
|
||||
}
|
||||
|
||||
int config_server_tcp(char *value)
|
||||
{
|
||||
return config_server(value, DNS_SERVER_TCP, DEFAULT_DNS_PORT);
|
||||
}
|
||||
|
||||
int config_tcp_idle_time(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int idle_time = atoi(value);
|
||||
if (idle_time < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_tcp_idle_time = idle_time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_server_tls(char *value)
|
||||
{
|
||||
return config_server(value, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
|
||||
}
|
||||
|
||||
int config_cache_size(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int cache_size = atoi(value);
|
||||
if (cache_size < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_cachesize = cache_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_cache_prefetch_domain(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
|
||||
dns_conf_prefetch = 1;
|
||||
} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
|
||||
dns_conf_prefetch = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_force_AAAA_SOA(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
|
||||
dns_conf_force_AAAA_SOA = 1;
|
||||
} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
|
||||
dns_conf_force_AAAA_SOA = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_log_level(char *value)
|
||||
{
|
||||
/* read log level and set */
|
||||
if (strncmp("debug", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_DEBUG;
|
||||
} else if (strncmp("info", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_INFO;
|
||||
} else if (strncmp("warn", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_WARN;
|
||||
} else if (strncmp("error", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_ERROR;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_log_file(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
strncpy(dns_conf_log_file, value, DNS_MAX_PATH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_log_size(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int base = 1;
|
||||
|
||||
if (strstr(value, "k") || strstr(value, "K")) {
|
||||
base = 1024;
|
||||
} else if (strstr(value, "m") || strstr(value, "M")) {
|
||||
base = 1024 * 1024;
|
||||
} else if (strstr(value, "g") || strstr(value, "G")) {
|
||||
base = 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
int size = atoi(value);
|
||||
if (size < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_log_size = size * base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_log_num(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int num = atoi(value);
|
||||
if (num < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_log_num = num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_audit_enable(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
|
||||
dns_conf_audit_enable = 1;
|
||||
} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
|
||||
dns_conf_audit_enable = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_audit_file(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
strncpy(dns_conf_audit_file, value, DNS_MAX_PATH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_audit_size(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int base = 1;
|
||||
|
||||
if (strstr(value, "k") || strstr(value, "K")) {
|
||||
base = 1024;
|
||||
} else if (strstr(value, "m") || strstr(value, "M")) {
|
||||
base = 1024 * 1024;
|
||||
} else if (strstr(value, "g") || strstr(value, "G")) {
|
||||
base = 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
int size = atoi(value);
|
||||
if (size < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_audit_size = size * base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_audit_num(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int num = atoi(value);
|
||||
if (num < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_audit_num = num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_rr_ttl(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int ttl = atoi(value);
|
||||
if (ttl < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_rr_ttl = ttl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_rr_ttl_min(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int ttl = atoi(value);
|
||||
if (ttl < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_rr_ttl_min = ttl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_rr_ttl_max(char *value)
|
||||
{
|
||||
/* read dns cache size */
|
||||
int ttl = atoi(value);
|
||||
if (ttl < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_rr_ttl_max = ttl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_bogus_nxdomain_exists(unsigned char *ip, dns_type_t addr_type)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_bogus_ip_address *ip_addr = NULL;
|
||||
int addr_len = 0;
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
addr_len = 4;
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
addr_len = 16;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
key = jhash(ip, addr_len, 0);
|
||||
hash_for_each_possible(dns_conf_bogus_nxdomain.ip_hash, ip_addr, node, key)
|
||||
{
|
||||
if (addr_type == DNS_T_A) {
|
||||
if (memcmp(ip_addr->ipv4_addr, ip, addr_len) == 0) {
|
||||
return 0;
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
if (memcmp(ip_addr->ipv6_addr, ip, addr_len) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void conf_bogus_nxdomain_destroy(void)
|
||||
{
|
||||
struct dns_bogus_ip_address *ip_addr = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
int i;
|
||||
|
||||
hash_for_each_safe(dns_conf_bogus_nxdomain.ip_hash, i, tmp, ip_addr, node)
|
||||
{
|
||||
hlist_del_init(&ip_addr->node);
|
||||
free(ip_addr);
|
||||
}
|
||||
}
|
||||
|
||||
radix_node_t *create_addr_node(radix_tree_t *tree, char *addr)
|
||||
{
|
||||
radix_node_t *node;
|
||||
void *p;
|
||||
prefix_t prefix;
|
||||
const char *errmsg = NULL;
|
||||
|
||||
p = prefix_pton(addr, -1, &prefix, &errmsg);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = radix_lookup(tree, &prefix);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
int config_iplist_action(char *subnet, enum address_action act)
|
||||
{
|
||||
radix_node_t *node = NULL;
|
||||
struct dns_ip_address_rule *ip_rule = NULL;
|
||||
|
||||
node = create_addr_node(dns_conf_address_rule, subnet);
|
||||
if (node == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node->data == NULL) {
|
||||
ip_rule = malloc(sizeof(*ip_rule));
|
||||
if (ip_rule == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->data = ip_rule;
|
||||
memset(ip_rule, 0, sizeof(*ip_rule));
|
||||
}
|
||||
|
||||
ip_rule = node->data;
|
||||
|
||||
switch (act) {
|
||||
case ACTION_BLACKLIST:
|
||||
ip_rule->blacklist = 1;
|
||||
break;
|
||||
case ACTION_BOGUS:
|
||||
ip_rule->bogus = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_blacklist_ip(char *value)
|
||||
{
|
||||
return config_iplist_action(value, ACTION_BLACKLIST);
|
||||
}
|
||||
|
||||
int conf_bogus_nxdomain(char *value)
|
||||
{
|
||||
//////////////////////////////////////
|
||||
config_iplist_action(value, ACTION_BOGUS);
|
||||
//////////////////////////////////////
|
||||
|
||||
struct dns_bogus_ip_address *ip_addr = NULL;
|
||||
char ip[MAX_IP_LEN];
|
||||
int port;
|
||||
int ret = -1;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
uint32_t key;
|
||||
|
||||
ip_addr = malloc(sizeof(*ip_addr));
|
||||
if (ip_addr == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memset(ip_addr, 0, sizeof(*ip_addr));
|
||||
|
||||
if (parse_ip(value, ip, &port) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
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(ip_addr->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
ip_addr->addr_type = DNS_T_A;
|
||||
addr_len = 4;
|
||||
} 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(ip_addr->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
ip_addr->addr_type = DNS_T_A;
|
||||
addr_len = 4;
|
||||
} else {
|
||||
memcpy(ip_addr->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
addr_len = 16;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (dns_bogus_nxdomain_exists(ip_addr->addr, ip_addr->addr_type) == 0) {
|
||||
ret = 0;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
key = jhash(ip_addr->addr, addr_len, 0);
|
||||
hash_add(dns_conf_bogus_nxdomain.ip_hash, &ip_addr->node, key);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (ip_addr) {
|
||||
free(ip_addr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int config_addtional_file(char *value)
|
||||
{
|
||||
char *file_path = value;
|
||||
|
||||
if (access(file_path, R_OK) != 0) {
|
||||
tlog(TLOG_WARN, "conf file %s is not readable.", file_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return load_conf_file(file_path);
|
||||
}
|
||||
|
||||
struct config_item {
|
||||
const char *item;
|
||||
int (*item_func)(char *value);
|
||||
};
|
||||
|
||||
struct config_item config_item[] = {
|
||||
{"server-name", config_server_name},
|
||||
{"bind", config_bind},
|
||||
{"bind-tcp", config_bind_tcp},
|
||||
{"server", config_server_udp},
|
||||
{"address", config_address},
|
||||
{"server-tcp", config_server_tcp},
|
||||
{"tcp-idle-time", config_tcp_idle_time},
|
||||
{"server-tls", config_server_tls},
|
||||
{"cache-size", config_cache_size},
|
||||
{"prefetch-domain", config_cache_prefetch_domain},
|
||||
{"log-level", config_log_level},
|
||||
{"log-file", config_log_file},
|
||||
{"log-size", config_log_size},
|
||||
{"log-num", config_log_num},
|
||||
{"audit-enable", config_audit_enable},
|
||||
{"audit-file", config_audit_file},
|
||||
{"audit-size", config_audit_size},
|
||||
{"audit-num", config_audit_num},
|
||||
{"rr-ttl", config_rr_ttl},
|
||||
{"rr-ttl-min", config_rr_ttl_min},
|
||||
{"rr-ttl-max", config_rr_ttl_max},
|
||||
{"force-AAAA-SOA", config_force_AAAA_SOA},
|
||||
{"blacklist-ip", config_blacklist_ip},
|
||||
{"bogus-nxdomain", conf_bogus_nxdomain},
|
||||
{"conf-file", config_addtional_file},
|
||||
};
|
||||
int config_item_num = sizeof(config_item) / sizeof(struct config_item);
|
||||
|
||||
int load_conf_init(void)
|
||||
{
|
||||
dns_conf_address_rule = New_Radix();
|
||||
art_tree_init(&dns_conf_domain_rule);
|
||||
if (dns_conf_address_rule == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hash_init(dns_conf_bogus_nxdomain.ip_hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_exit(void)
|
||||
{
|
||||
conf_bogus_nxdomain_destroy();
|
||||
config_domain_destroy();
|
||||
Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
|
||||
}
|
||||
|
||||
int load_conf_file(const char *file)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char line[MAX_LINE_LEN];
|
||||
char key[MAX_KEY_LEN];
|
||||
char value[MAX_LINE_LEN];
|
||||
int filed_num = 0;
|
||||
int line_num = 0;
|
||||
int i;
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
tlog(TLOG_ERROR, "config file %s not exist.", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(line, MAX_LINE_LEN, fp)) {
|
||||
line_num++;
|
||||
filed_num = sscanf(line, "%63s %1023[^\r\n]s", key, value);
|
||||
if (filed_num <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* comment, skip */
|
||||
if (key[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if field format is not key = value, error */
|
||||
if (filed_num != 2) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for (i = 0; i < config_item_num; i++) {
|
||||
if (strncmp(config_item[i].item, key, MAX_KEY_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* call item function */
|
||||
if (config_item[i].item_func(value) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
printf("invalid config at file %s:%d, %s", file, line_num, line);
|
||||
tlog(TLOG_ERROR, "invalid config at file %s:%d, %s", file, line_num, line);
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int load_conf(const char *file)
|
||||
{
|
||||
load_conf_init();
|
||||
|
||||
return load_conf_file(file);
|
||||
}
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -42,8 +44,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#define DNS_MAX_HOSTNAME 256
|
||||
#define DNS_MAX_EVENTS 64
|
||||
@@ -97,6 +97,7 @@ struct dns_server_info {
|
||||
SSL *ssl;
|
||||
SSL_CTX *ssl_ctx;
|
||||
dns_server_status status;
|
||||
unsigned int result_flag;
|
||||
|
||||
struct dns_server_buff send_buff;
|
||||
struct dns_server_buff recv_buff;
|
||||
@@ -155,7 +156,6 @@ struct dns_query_struct {
|
||||
static struct dns_client client;
|
||||
static atomic_t dns_client_sid = ATOMIC_INIT(0);
|
||||
|
||||
|
||||
/* get addr info */
|
||||
static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol)
|
||||
{
|
||||
@@ -211,7 +211,7 @@ int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t server_type
|
||||
}
|
||||
|
||||
/* 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, int result_flag)
|
||||
{
|
||||
struct dns_server_info *server_info = NULL;
|
||||
|
||||
@@ -229,6 +229,7 @@ int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_typ
|
||||
server_info->type = server_type;
|
||||
server_info->fd = 0;
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
server_info->result_flag = result_flag;
|
||||
|
||||
if (gai->ai_addrlen > sizeof(server_info->in6)) {
|
||||
tlog(TLOG_ERROR, "addr len invalid, %d, %zd, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ai_family);
|
||||
@@ -336,7 +337,7 @@ int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_server_
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, int operate)
|
||||
int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, int result_flag, int operate)
|
||||
{
|
||||
char port_s[8];
|
||||
int sock_type;
|
||||
@@ -370,7 +371,7 @@ int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t serv
|
||||
}
|
||||
|
||||
if (operate == 0) {
|
||||
ret = _dns_client_server_add(server_ip, gai, server_type);
|
||||
ret = _dns_client_server_add(server_ip, gai, server_type, result_flag);
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
@@ -389,14 +390,14 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
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, int result_flag)
|
||||
{
|
||||
return _dns_client_server_operate(server_ip, port, server_type, 0);
|
||||
return _dns_client_server_operate(server_ip, port, server_type, result_flag, 0);
|
||||
}
|
||||
|
||||
int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type)
|
||||
{
|
||||
return _dns_client_server_operate(server_ip, port, server_type, 1);
|
||||
return _dns_client_server_operate(server_ip, port, server_type, 0, 1);
|
||||
}
|
||||
|
||||
int dns_server_num(void)
|
||||
@@ -426,7 +427,7 @@ void _dns_client_query_release(struct dns_query_struct *query)
|
||||
|
||||
/* notify caller query end */
|
||||
if (query->callback) {
|
||||
query->callback(query->domain, DNS_QUERY_END, NULL, NULL, 0, query->user_ptr);
|
||||
query->callback(query->domain, DNS_QUERY_END, 0, NULL, NULL, 0, query->user_ptr);
|
||||
}
|
||||
|
||||
/* free resource */
|
||||
@@ -587,7 +588,7 @@ int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr *from, socklen_t from_len)
|
||||
static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *inpacket, int inpacket_len, struct sockaddr *from, socklen_t from_len)
|
||||
{
|
||||
int len;
|
||||
int i;
|
||||
@@ -609,7 +610,7 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
|
||||
if (len != 0) {
|
||||
char host_name[DNS_MAX_CNAME_LEN];
|
||||
tlog(TLOG_ERROR, "decode failed, packet len = %d, tc = %d, id = %d, from = %s\n", inpacket_len, packet->head.tc, packet->head.id,
|
||||
gethost_by_addr(host_name, from, from_len));
|
||||
gethost_by_addr(host_name, from, from_len));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -649,12 +650,11 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
|
||||
|
||||
/* notify caller dns query result */
|
||||
if (query->callback) {
|
||||
ret = query->callback(query->domain, DNS_QUERY_RESULT, packet, inpacket, inpacket_len, query->user_ptr);
|
||||
}
|
||||
|
||||
if (request_num == 0 || ret) {
|
||||
/* if all server replied, or done, stop query, release resource */
|
||||
_dns_client_query_remove(query);
|
||||
ret = query->callback(query->domain, DNS_QUERY_RESULT, server_info->result_flag, packet, inpacket, inpacket_len, query->user_ptr);
|
||||
if (request_num == 0 || ret) {
|
||||
/* if all server replied, or done, stop query, release resource */
|
||||
_dns_client_query_remove(query);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -771,7 +771,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info)
|
||||
}
|
||||
}
|
||||
|
||||
if(SSL_set_fd(ssl, fd) == 0) {
|
||||
if (SSL_set_fd(ssl, fd) == 0) {
|
||||
tlog(TLOG_ERROR, "ssl set fd failed.");
|
||||
goto errout;
|
||||
}
|
||||
@@ -844,7 +844,7 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
|
||||
tlog(TLOG_DEBUG, "recv udp, from %s", gethost_by_addr(from_host, (struct sockaddr *)&from, from_len));
|
||||
|
||||
time(&server_info->last_recv);
|
||||
if (_dns_client_recv(inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
|
||||
if (_dns_client_recv(server_info, inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -866,7 +866,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
if (errno == EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FOR GFW */
|
||||
if (errno == ECONNRESET) {
|
||||
goto errout;
|
||||
@@ -901,9 +901,9 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/* tcp result format
|
||||
* | len (short) | dns query result |
|
||||
*/
|
||||
/* tcp result format
|
||||
* | len (short) | dns query result |
|
||||
*/
|
||||
inpacket_data = server_info->recv_buff.data;
|
||||
len = ntohs(*((unsigned short *)(inpacket_data)));
|
||||
if (len <= 0 || len >= DNS_IN_PACKSIZE) {
|
||||
@@ -920,7 +920,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len);
|
||||
|
||||
/* process result */
|
||||
if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (_dns_client_recv(server_info, inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
len += 2;
|
||||
@@ -1109,9 +1109,9 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
char peer_CN[256];
|
||||
const EVP_MD * digest;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
unsigned int n;
|
||||
const EVP_MD *digest;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
unsigned int n;
|
||||
char cert_fingerprint[256];
|
||||
int i = 0;
|
||||
|
||||
@@ -1194,7 +1194,6 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (event->events & EPOLLIN) {
|
||||
@@ -1205,7 +1204,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
if (errno == EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FOR GFW */
|
||||
if (errno == ECONNRESET) {
|
||||
goto errout;
|
||||
@@ -1240,9 +1239,9 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/* tcp result format
|
||||
* | len (short) | dns query result |
|
||||
*/
|
||||
/* tcp result format
|
||||
* | len (short) | dns query result |
|
||||
*/
|
||||
inpacket_data = server_info->recv_buff.data;
|
||||
len = ntohs(*((unsigned short *)(inpacket_data)));
|
||||
if (len <= 0 || len >= DNS_IN_PACKSIZE) {
|
||||
@@ -1259,7 +1258,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len);
|
||||
|
||||
/* process result */
|
||||
if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (_dns_client_recv(server_info, inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
len += 2;
|
||||
@@ -1423,7 +1422,7 @@ static int _dns_client_send_tcp(struct dns_server_info *server_info, void *packe
|
||||
unsigned char *inpacket = inpacket_data;
|
||||
|
||||
/* TCP query format
|
||||
* | len (short) | dns query data |
|
||||
* | len (short) | dns query data |
|
||||
*/
|
||||
*((unsigned short *)(inpacket)) = htons(len);
|
||||
memcpy(inpacket + 2, packet, len);
|
||||
@@ -1451,7 +1450,7 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
|
||||
unsigned char *inpacket = inpacket_data;
|
||||
|
||||
/* TCP query format
|
||||
* | len (short) | dns query data |
|
||||
* | len (short) | dns query data |
|
||||
*/
|
||||
*((unsigned short *)(inpacket)) = htons(len);
|
||||
memcpy(inpacket + 2, packet, len);
|
||||
|
||||
@@ -16,10 +16,12 @@ typedef enum dns_result_type {
|
||||
DNS_QUERY_END,
|
||||
} dns_result_type;
|
||||
|
||||
#define DNSSERVER_FLAG_BLACKLIST_IP (0x1 << 0)
|
||||
|
||||
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, unsigned int result_flag, 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);
|
||||
@@ -27,7 +29,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, 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, int result_flag);
|
||||
|
||||
/* remove remote dns server */
|
||||
int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type);
|
||||
|
||||
443
src/dns_conf.c
Normal file
443
src/dns_conf.c
Normal file
@@ -0,0 +1,443 @@
|
||||
#include "dns_conf.h"
|
||||
#include "list.h"
|
||||
#include "rbtree.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEFAULT_DNS_CACHE_SIZE 512
|
||||
|
||||
char dns_conf_server_ip[DNS_MAX_IPLEN];
|
||||
char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
||||
int dns_conf_tcp_idle_time = 120;
|
||||
int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
|
||||
int dns_conf_server_num;
|
||||
int dns_conf_log_level = TLOG_ERROR;
|
||||
char dns_conf_log_file[DNS_MAX_PATH];
|
||||
size_t dns_conf_log_size = 1024 * 1024;
|
||||
int dns_conf_log_num = 8;
|
||||
int dns_conf_audit_enable = 0;
|
||||
char dns_conf_audit_file[DNS_MAX_PATH];
|
||||
size_t dns_conf_audit_size = 1024 * 1024;
|
||||
int dns_conf_audit_num = 2;
|
||||
|
||||
art_tree dns_conf_domain_rule;
|
||||
radix_tree_t *dns_conf_address_rule;
|
||||
|
||||
int dns_conf_rr_ttl;
|
||||
int dns_conf_rr_ttl_min;
|
||||
int dns_conf_rr_ttl_max;
|
||||
int dns_conf_force_AAAA_SOA;
|
||||
|
||||
int config_server(int argc, char *argv[], dns_server_type_t type, int default_port)
|
||||
{
|
||||
int index = dns_conf_server_num;
|
||||
struct dns_servers *server;
|
||||
int port = -1;
|
||||
char *ip = NULL;
|
||||
int opt = 0;
|
||||
int result_flag = 0;
|
||||
/* clang-format off */
|
||||
static struct option long_options[] = {
|
||||
{"blacklist-ip", 0, 0, 'b'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
/* clang-format on */
|
||||
if (argc <= 1) {
|
||||
tlog(TLOG_ERROR, "invalid parameter.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
optind = 1;
|
||||
while (1) {
|
||||
opt = getopt_long_only(argc, argv, "", long_options, NULL);
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (opt) {
|
||||
case 'b': {
|
||||
result_flag |= DNSSERVER_FLAG_BLACKLIST_IP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_ERROR, "exceeds max server number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
server = &dns_conf_servers[index];
|
||||
/* parse ip, port from ip */
|
||||
if (parse_ip(ip, server->server, &port) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if port is not defined, set port to default 53 */
|
||||
if (port == PORT_NOT_DEFINED) {
|
||||
port = default_port;
|
||||
}
|
||||
|
||||
server->type = type;
|
||||
server->port = port;
|
||||
server->result_flag = result_flag;
|
||||
dns_conf_server_num++;
|
||||
tlog(TLOG_DEBUG, "add server %s, flag: %X", ip, result_flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_domain_iter_cb(void *data, const unsigned char *key, uint32_t key_len, void *value)
|
||||
{
|
||||
struct dns_domain_rule *domain_rule = value;
|
||||
int i = 0;
|
||||
|
||||
if (domain_rule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < DOMAIN_RULE_MAX; i++) {
|
||||
free(domain_rule->rules[i]);
|
||||
}
|
||||
|
||||
free(domain_rule);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_domain_destroy(void)
|
||||
{
|
||||
art_iter(&dns_conf_domain_rule, config_domain_iter_cb, 0);
|
||||
art_tree_destroy(&dns_conf_domain_rule);
|
||||
}
|
||||
|
||||
void config_address_destroy(radix_node_t *node, void *cbctx)
|
||||
{
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(node->data);
|
||||
node->data = NULL;
|
||||
}
|
||||
|
||||
int config_domain_rule_add(char *domain, enum domain_rule type, void *rule)
|
||||
{
|
||||
struct dns_domain_rule *domain_rule = NULL;
|
||||
struct dns_domain_rule *old_domain_rule = NULL;
|
||||
struct dns_domain_rule *add_domain_rule = NULL;
|
||||
|
||||
char domain_key[DNS_MAX_CONF_CNAME_LEN];
|
||||
int len = 0;
|
||||
|
||||
len = strlen(domain);
|
||||
reverse_string(domain_key, domain, len);
|
||||
domain_key[len] = '.';
|
||||
len++;
|
||||
domain_key[len] = 0;
|
||||
|
||||
if (type >= DOMAIN_RULE_MAX) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
domain_rule = art_search(&dns_conf_domain_rule, (unsigned char *)domain_key, len);
|
||||
if (domain_rule == NULL) {
|
||||
add_domain_rule = malloc(sizeof(*add_domain_rule));
|
||||
if (add_domain_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memset(add_domain_rule, 0, sizeof(*add_domain_rule));
|
||||
domain_rule = add_domain_rule;
|
||||
}
|
||||
|
||||
if (domain_rule->rules[type]) {
|
||||
free(domain_rule->rules[type]);
|
||||
domain_rule->rules[type] = NULL;
|
||||
}
|
||||
|
||||
domain_rule->rules[type] = rule;
|
||||
|
||||
if (add_domain_rule) {
|
||||
old_domain_rule = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, add_domain_rule);
|
||||
if (old_domain_rule) {
|
||||
free(old_domain_rule);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (add_domain_rule) {
|
||||
free(add_domain_rule);
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "add doamin %s failed", domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_address(void *data, int argc, char *argv[])
|
||||
{
|
||||
struct dns_address_IPV4 *address_ipv4 = NULL;
|
||||
struct dns_address_IPV6 *address_ipv6 = NULL;
|
||||
void *address = NULL;
|
||||
char *value = argv[1];
|
||||
char ip[MAX_IP_LEN];
|
||||
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||
char *begin = NULL;
|
||||
char *end = NULL;
|
||||
int len = 0;
|
||||
int port;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
enum domain_rule type = 0;
|
||||
|
||||
begin = strstr(value, "/");
|
||||
if (begin == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
begin++;
|
||||
end = strstr(begin, "/");
|
||||
if (end == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* remove prefix . */
|
||||
while (*begin == '.') {
|
||||
begin++;
|
||||
}
|
||||
|
||||
len = end - begin;
|
||||
memcpy(domain, begin, len);
|
||||
domain[len] = 0;
|
||||
|
||||
if (parse_ip(end + 1, ip, &port) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
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;
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
if (address_ipv4 == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
memcpy(address_ipv4->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV4;
|
||||
address = address_ipv4;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
if (address_ipv4 == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(address_ipv4->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV4;
|
||||
address = address_ipv4;
|
||||
} else {
|
||||
address_ipv6 = malloc(sizeof(*address_ipv6));
|
||||
if (address_ipv6 == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(address_ipv6->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV6;
|
||||
address = address_ipv6;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (config_domain_rule_add(domain, type, address) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (address) {
|
||||
free(address);
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "add address %s failed", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_server_udp(void *data, int argc, char *argv[])
|
||||
{
|
||||
return config_server(argc, argv, DNS_SERVER_UDP, DEFAULT_DNS_PORT);
|
||||
}
|
||||
|
||||
int config_server_tcp(void *data, int argc, char *argv[])
|
||||
{
|
||||
return config_server(argc, argv, DNS_SERVER_TCP, DEFAULT_DNS_PORT);
|
||||
}
|
||||
|
||||
int config_server_tls(void *data, int argc, char *argv[])
|
||||
{
|
||||
return config_server(argc, argv, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
|
||||
}
|
||||
|
||||
radix_node_t *create_addr_node(radix_tree_t *tree, char *addr)
|
||||
{
|
||||
radix_node_t *node;
|
||||
void *p;
|
||||
prefix_t prefix;
|
||||
const char *errmsg = NULL;
|
||||
|
||||
p = prefix_pton(addr, -1, &prefix, &errmsg);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = radix_lookup(tree, &prefix);
|
||||
return node;
|
||||
}
|
||||
|
||||
int config_iplist_rule(char *subnet, enum address_rule rule)
|
||||
{
|
||||
radix_node_t *node = NULL;
|
||||
struct dns_ip_address_rule *ip_rule = NULL;
|
||||
|
||||
node = create_addr_node(dns_conf_address_rule, subnet);
|
||||
if (node == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node->data == NULL) {
|
||||
ip_rule = malloc(sizeof(*ip_rule));
|
||||
if (ip_rule == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->data = ip_rule;
|
||||
memset(ip_rule, 0, sizeof(*ip_rule));
|
||||
}
|
||||
|
||||
ip_rule = node->data;
|
||||
|
||||
switch (rule) {
|
||||
case ADDRESS_RULE_BLACKLIST:
|
||||
ip_rule->blacklist = 1;
|
||||
break;
|
||||
case ADDRESS_RULE_BOGUS:
|
||||
ip_rule->bogus = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_blacklist_ip(void *data, int argc, char *argv[])
|
||||
{
|
||||
return config_iplist_rule(argv[1], ADDRESS_RULE_BLACKLIST);
|
||||
}
|
||||
|
||||
int conf_bogus_nxdomain(void *data, int argc, char *argv[])
|
||||
{
|
||||
return config_iplist_rule(argv[1], ADDRESS_RULE_BOGUS);
|
||||
}
|
||||
|
||||
int config_log_level(void *data, int argc, char *argv[])
|
||||
{
|
||||
/* read log level and set */
|
||||
char *value = argv[1];
|
||||
|
||||
if (strncmp("debug", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_DEBUG;
|
||||
} else if (strncmp("info", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_INFO;
|
||||
} else if (strncmp("warn", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_WARN;
|
||||
} else if (strncmp("error", value, MAX_LINE_LEN) == 0) {
|
||||
dns_conf_log_level = TLOG_ERROR;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct config_item config_item[] = {
|
||||
CONF_STRING("server-name", (char *)dns_conf_server_name, DNS_MAX_CONF_CNAME_LEN),
|
||||
CONF_STRING("bind", dns_conf_server_ip, DNS_MAX_IPLEN),
|
||||
CONF_STRING("bind-tcp", dns_conf_server_tcp_ip, DNS_MAX_IPLEN),
|
||||
CONF_CUSTOM("server", config_server_udp, NULL),
|
||||
CONF_CUSTOM("server-tcp", config_server_tcp, NULL),
|
||||
CONF_CUSTOM("server-tls", config_server_tls, NULL),
|
||||
CONF_CUSTOM("address", config_address, NULL),
|
||||
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
||||
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
|
||||
CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
|
||||
CONF_CUSTOM("log-level", config_log_level, NULL),
|
||||
CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH),
|
||||
CONF_SIZE("log-size", &dns_conf_log_size, 0, 1024 * 1024 * 1024),
|
||||
CONF_INT("log-num", &dns_conf_log_num, 0, 1024),
|
||||
CONF_YESNO("audit-enable", &dns_conf_audit_enable),
|
||||
CONF_STRING("audit-file", (char *)&dns_conf_audit_file, DNS_MAX_PATH),
|
||||
CONF_SIZE("audit-size", &dns_conf_audit_size, 0, 1024 * 1024 * 1024),
|
||||
CONF_INT("audit-num", &dns_conf_audit_num, 0, 1024),
|
||||
CONF_INT("rr-ttl", &dns_conf_rr_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-min", &dns_conf_rr_ttl_min, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
|
||||
CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
|
||||
CONF_CUSTOM("blacklist-ip", config_blacklist_ip, NULL),
|
||||
CONF_CUSTOM("bogus-nxdomain", conf_bogus_nxdomain, NULL),
|
||||
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
||||
CONF_END(),
|
||||
};
|
||||
|
||||
int config_addtional_file(void *data, int argc, char *argv[])
|
||||
{
|
||||
char *file_path = argv[1];
|
||||
|
||||
if (access(file_path, R_OK) != 0) {
|
||||
tlog(TLOG_WARN, "conf file %s is not readable.", file_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return load_conf(file_path, config_item);
|
||||
}
|
||||
|
||||
int _dns_server_load_conf_init(void)
|
||||
{
|
||||
dns_conf_address_rule = New_Radix();
|
||||
art_tree_init(&dns_conf_domain_rule);
|
||||
if (dns_conf_address_rule == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dns_server_load_exit(void)
|
||||
{
|
||||
config_domain_destroy();
|
||||
Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
|
||||
}
|
||||
|
||||
int dns_server_load_conf(const char *file)
|
||||
{
|
||||
_dns_server_load_conf_init();
|
||||
|
||||
return load_conf(file, config_item);
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef _DNS_CONF
|
||||
#define _DNS_CONF
|
||||
|
||||
#include "list.h"
|
||||
#include "art.h"
|
||||
#include "radix.h"
|
||||
#include "conf.h"
|
||||
#include "dns.h"
|
||||
#include "dns_client.h"
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "radix.h"
|
||||
|
||||
#define DNS_MAX_SERVERS 32
|
||||
#define DNS_MAX_IPLEN 64
|
||||
@@ -19,21 +20,31 @@
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
|
||||
|
||||
enum domain_rule {
|
||||
DOMAIN_RULE_ADDRESS_IPV4 = 1,
|
||||
DOMAIN_RULE_ADDRESS_IPV6 = 2,
|
||||
DOMAIN_RULE_MAX,
|
||||
};
|
||||
|
||||
struct dns_address_IPV4 {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
};
|
||||
|
||||
struct dns_address_IPV6 {
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
};
|
||||
|
||||
struct dns_domain_rule {
|
||||
void *rules[DOMAIN_RULE_MAX];
|
||||
};
|
||||
|
||||
struct dns_servers {
|
||||
char server[DNS_MAX_IPLEN];
|
||||
unsigned short port;
|
||||
unsigned int result_flag;
|
||||
dns_server_type_t type;
|
||||
};
|
||||
|
||||
struct dns_address {
|
||||
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];
|
||||
};
|
||||
};
|
||||
|
||||
/* ip address lists of domain */
|
||||
struct dns_bogus_ip_address {
|
||||
struct hlist_node node;
|
||||
@@ -45,13 +56,12 @@ struct dns_bogus_ip_address {
|
||||
};
|
||||
};
|
||||
|
||||
enum address_action {
|
||||
ACTION_BLACKLIST = 1,
|
||||
ACTION_BOGUS = 2,
|
||||
enum address_rule {
|
||||
ADDRESS_RULE_BLACKLIST = 1,
|
||||
ADDRESS_RULE_BOGUS = 2,
|
||||
};
|
||||
|
||||
struct dns_ip_address_rule
|
||||
{
|
||||
struct dns_ip_address_rule {
|
||||
unsigned int blacklist : 1;
|
||||
unsigned int bogus : 1;
|
||||
};
|
||||
@@ -68,16 +78,14 @@ extern int dns_conf_prefetch;
|
||||
extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
extern int dns_conf_server_num;
|
||||
|
||||
extern struct dns_bogus_nxdomain dns_conf_bogus_nxdomain;
|
||||
|
||||
extern int dns_conf_log_level;
|
||||
extern char dns_conf_log_file[DNS_MAX_PATH];
|
||||
extern int dns_conf_log_size;
|
||||
extern size_t dns_conf_log_size;
|
||||
extern int dns_conf_log_num;
|
||||
|
||||
extern int dns_conf_audit_enable;
|
||||
extern char dns_conf_audit_file[DNS_MAX_PATH];
|
||||
extern int dns_conf_audit_size;
|
||||
extern size_t dns_conf_audit_size;
|
||||
extern int dns_conf_audit_num;
|
||||
|
||||
extern char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
|
||||
@@ -89,10 +97,10 @@ extern int dns_conf_rr_ttl_min;
|
||||
extern int dns_conf_rr_ttl_max;
|
||||
extern int dns_conf_force_AAAA_SOA;
|
||||
|
||||
int dns_bogus_nxdomain_exists(unsigned char *ip, dns_type_t addr_type);
|
||||
void dns_server_load_exit(void);
|
||||
|
||||
int load_conf(const char *file);
|
||||
int dns_server_load_conf(const char *file);
|
||||
|
||||
void load_exit(void);
|
||||
extern int config_addtional_file(void *data, int argc, char *argv[]);
|
||||
|
||||
#endif // !_DNS_CONF
|
||||
201
src/dns_server.c
201
src/dns_server.c
@@ -18,7 +18,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "dns_server.h"
|
||||
#include "atomic.h"
|
||||
#include "conf.h"
|
||||
#include "dns_conf.h"
|
||||
#include "dns.h"
|
||||
#include "dns_cache.h"
|
||||
#include "dns_client.h"
|
||||
@@ -85,7 +85,6 @@ struct dns_server {
|
||||
struct list_head client_list;
|
||||
};
|
||||
|
||||
|
||||
/* ip address lists of domain */
|
||||
struct dns_ip_address {
|
||||
struct hlist_node node;
|
||||
@@ -153,9 +152,11 @@ struct dns_request {
|
||||
int prefetch;
|
||||
|
||||
pthread_mutex_t ip_map_lock;
|
||||
|
||||
|
||||
int ip_map_num;
|
||||
DECLARE_HASHTABLE(ip_map, 4);
|
||||
|
||||
struct dns_domain_rule *domain_rule;
|
||||
};
|
||||
|
||||
static struct dns_server server;
|
||||
@@ -180,13 +181,12 @@ static void _dns_server_audit_log(struct dns_request *request)
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_AAAA) {
|
||||
snprintf(req_result, sizeof(req_result), "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5],
|
||||
request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11],
|
||||
request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
|
||||
snprintf(req_result, sizeof(req_result), "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->ipv6_addr[0],
|
||||
request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
|
||||
request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11], request->ipv6_addr[12],
|
||||
request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
|
||||
} else if (request->qtype == DNS_T_A) {
|
||||
snprintf(req_result, sizeof(req_result), "%d.%d.%d.%d", request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2],
|
||||
request->ipv4_addr[3]);
|
||||
snprintf(req_result, sizeof(req_result), "%d.%d.%d.%d", request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -324,7 +324,7 @@ static int _dns_server_reply_tcp(struct dns_server_conn *client, void *packet, u
|
||||
unsigned char *inpacket = inpacket_data;
|
||||
|
||||
/* TCP query format
|
||||
* | len (short) | dns query data |
|
||||
* | len (short) | dns query data |
|
||||
*/
|
||||
*((unsigned short *)(inpacket)) = htons(len);
|
||||
memcpy(inpacket + 2, packet, len);
|
||||
@@ -372,8 +372,6 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
_dns_server_client_release(client);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -667,23 +665,7 @@ static int _dns_server_get_conf_ttl(int ttl)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
static int _dns_server_bogus_nxdomain_exists(struct dns_request *request, unsigned char *ip, dns_type_t addr_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = dns_bogus_nxdomain_exists(ip, addr_type);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (request->rcode == DNS_RC_SERVFAIL) {
|
||||
request->rcode = DNS_RC_NXDOMAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len, dns_type_t addr_type)
|
||||
static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len, dns_type_t addr_type, int result_flag)
|
||||
{
|
||||
prefix_t prefix;
|
||||
radix_node_t *node = NULL;
|
||||
@@ -695,7 +677,7 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
|
||||
|
||||
node = radix_search_best(dns_conf_address_rule, &prefix);
|
||||
if (node == NULL) {
|
||||
return - 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node->data == NULL) {
|
||||
@@ -703,11 +685,26 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
|
||||
}
|
||||
|
||||
rule = node->data;
|
||||
if (rule->bogus) {
|
||||
goto match;
|
||||
}
|
||||
|
||||
if (rule->blacklist) {
|
||||
if (result_flag & DNSSERVER_FLAG_BLACKLIST_IP) {
|
||||
goto match;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
match:
|
||||
if (request->rcode == DNS_RC_SERVFAIL) {
|
||||
request->rcode = DNS_RC_NXDOMAIN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet)
|
||||
static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet, unsigned int result_flag)
|
||||
{
|
||||
int ttl;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
@@ -741,18 +738,12 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
||||
|
||||
if (_dns_server_ip_rule_check(request, addr, 4, DNS_T_A) == 0) {
|
||||
/* ip rule check */
|
||||
if (_dns_server_ip_rule_check(request, addr, 4, DNS_T_A, result_flag) == 0) {
|
||||
_dns_server_request_release(request);
|
||||
break;
|
||||
}
|
||||
|
||||
/* bogus ip address, skip */
|
||||
if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_A) == 0) {
|
||||
_dns_server_request_release(request);
|
||||
tlog(TLOG_DEBUG, "bogus-nxdomain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
_dns_server_request_release(request);
|
||||
break;
|
||||
@@ -799,20 +790,11 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, addr[0], addr[1],
|
||||
addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
|
||||
if (_dns_server_ip_rule_check(request, addr, 16, DNS_T_A) == 0) {
|
||||
if (_dns_server_ip_rule_check(request, addr, 16, DNS_T_AAAA, result_flag) == 0) {
|
||||
_dns_server_request_release(request);
|
||||
break;
|
||||
}
|
||||
|
||||
/* bogus ip address, skip */
|
||||
if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_AAAA) == 0) {
|
||||
_dns_server_request_release(request);
|
||||
tlog(TLOG_DEBUG, "bogus-nxdomain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl,
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13],
|
||||
addr[14], addr[15]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
_dns_server_request_release(request);
|
||||
break;
|
||||
@@ -886,10 +868,11 @@ static int dns_server_update_reply_packet_id(struct dns_request *request, unsign
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dns_server_resolve_callback(char *domain, dns_result_type rtype, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
|
||||
static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsigned int result_flag, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
|
||||
void *user_ptr)
|
||||
{
|
||||
struct dns_request *request = user_ptr;
|
||||
struct dns_server_conn *client = request->client;
|
||||
int ip_num = 0;
|
||||
|
||||
if (request == NULL) {
|
||||
@@ -900,9 +883,10 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, stru
|
||||
if (request->passthrough) {
|
||||
dns_server_update_reply_packet_id(request, inpacket, inpacket_len);
|
||||
_dns_reply_inpacket(request, inpacket, inpacket_len);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
_dns_server_process_answer(request, domain, packet);
|
||||
|
||||
_dns_server_process_answer(request, domain, packet, result_flag);
|
||||
return 0;
|
||||
} else if (rtype == DNS_QUERY_ERR) {
|
||||
tlog(TLOG_ERROR, "request faield, %s", domain);
|
||||
@@ -921,6 +905,7 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, stru
|
||||
_dns_server_request_remove(request);
|
||||
}
|
||||
_dns_server_request_release(request);
|
||||
_dns_server_client_release(client);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1023,35 +1008,26 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request, struct
|
||||
static void _dns_server_log_rule(char *domain, unsigned char *rule_key, int rule_key_len)
|
||||
{
|
||||
char rule_name[DNS_MAX_CNAME_LEN];
|
||||
|
||||
if (rule_key_len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
reverse_string(rule_name, (char *)rule_key, rule_key_len);
|
||||
rule_name[rule_key_len - 1] = 0;
|
||||
rule_name[rule_key_len] = 0;
|
||||
tlog(TLOG_INFO, "RULE-MATCH, domain: %s, rule: %s", domain, rule_name);
|
||||
}
|
||||
|
||||
static struct dns_address *_dns_server_get_address_by_domain(char *domain, int qtype)
|
||||
static struct dns_domain_rule *_dns_server_get_domain_rule(char *domain)
|
||||
{
|
||||
int domain_len;
|
||||
char domain_key[DNS_MAX_CNAME_LEN];
|
||||
char type = '4';
|
||||
unsigned char matched_key[DNS_MAX_CNAME_LEN];
|
||||
int matched_key_len = DNS_MAX_CNAME_LEN;
|
||||
struct dns_address *address = NULL;
|
||||
|
||||
switch (qtype) {
|
||||
case DNS_T_A:
|
||||
type = '4';
|
||||
break;
|
||||
case DNS_T_AAAA:
|
||||
type = '6';
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
unsigned char matched_key[DNS_MAX_CNAME_LEN];
|
||||
struct dns_domain_rule *domain_rule = NULL;
|
||||
|
||||
domain_len = strlen(domain);
|
||||
reverse_string(domain_key + 1, domain, domain_len);
|
||||
domain_key[0] = type;
|
||||
domain_len++;
|
||||
reverse_string(domain_key, domain, domain_len);
|
||||
domain_key[domain_len] = '.';
|
||||
domain_len++;
|
||||
domain_key[domain_len] = 0;
|
||||
@@ -1060,37 +1036,47 @@ static struct dns_address *_dns_server_get_address_by_domain(char *domain, int q
|
||||
return art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, NULL, NULL);
|
||||
}
|
||||
|
||||
address = art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, matched_key, &matched_key_len);
|
||||
if (address == NULL) {
|
||||
domain_rule = art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, matched_key, &matched_key_len);
|
||||
if (domain_rule == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (matched_key_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
matched_key_len--;
|
||||
matched_key[matched_key_len] = 0;
|
||||
_dns_server_log_rule(domain, matched_key, matched_key_len);
|
||||
|
||||
return address;
|
||||
return domain_rule;
|
||||
}
|
||||
|
||||
static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
struct dns_address *address = NULL;
|
||||
struct dns_address_IPV4 *address_ipv4 = NULL;
|
||||
struct dns_address_IPV6 *address_ipv6 = NULL;
|
||||
|
||||
address = _dns_server_get_address_by_domain(request->domain, request->qtype);
|
||||
if (address == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->qtype != address->addr_type) {
|
||||
if (request->domain_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
switch (request->qtype) {
|
||||
case DNS_T_A:
|
||||
memcpy(request->ipv4_addr, address->ipv4_addr, DNS_RR_A_LEN);
|
||||
if (request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV4] == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
address_ipv4 = request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV4];
|
||||
memcpy(request->ipv4_addr, address_ipv4->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);
|
||||
if (request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV6] == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
address_ipv6 = request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV6];
|
||||
memcpy(request->ipv6_addr, address_ipv6->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
request->ttl_v6 = 600;
|
||||
request->has_ipv6 = 1;
|
||||
break;
|
||||
@@ -1174,9 +1160,9 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "request qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = %d, rcode = %d\n", packet->head.qdcount,
|
||||
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);
|
||||
tlog(TLOG_DEBUG, "request qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = %d, rcode = %d\n",
|
||||
packet->head.qdcount, 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);
|
||||
|
||||
if (packet->head.qr != DNS_QR_QUERY) {
|
||||
goto errout;
|
||||
@@ -1187,6 +1173,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
tlog(TLOG_ERROR, "malloc failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(request, 0, sizeof(*request));
|
||||
pthread_mutex_init(&request->ip_map_lock, 0);
|
||||
atomic_set(&request->adblock, 0);
|
||||
@@ -1219,12 +1206,13 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
request->qtype = qtype;
|
||||
}
|
||||
|
||||
request->domain_rule = _dns_server_get_domain_rule(request->domain);
|
||||
|
||||
switch (qtype) {
|
||||
case DNS_T_PTR:
|
||||
ret = _dns_server_process_ptr(request, packet);
|
||||
if (ret == 0) {
|
||||
free(request);
|
||||
return ret;
|
||||
goto clean_exit;
|
||||
} else {
|
||||
request->passthrough = 1;
|
||||
}
|
||||
@@ -1234,8 +1222,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
case DNS_T_AAAA:
|
||||
if (dns_conf_force_AAAA_SOA == 1) {
|
||||
_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
|
||||
free(request);
|
||||
return 0;
|
||||
goto clean_exit;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1245,13 +1232,11 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
}
|
||||
|
||||
if (_dns_server_process_address(request, packet) == 0) {
|
||||
free(request);
|
||||
return 0;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (_dns_server_process_cache(request, packet) == 0) {
|
||||
free(request);
|
||||
return 0;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, gethost_by_addr(name, (struct sockaddr *)from, from_len), qtype);
|
||||
@@ -1265,6 +1250,14 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
request->send_tick = get_tick_count();
|
||||
dns_client_query(request->domain, qtype, dns_server_resolve_callback, request);
|
||||
|
||||
return 0;
|
||||
clean_exit:
|
||||
if (request) {
|
||||
free(request);
|
||||
}
|
||||
|
||||
_dns_server_client_release(client);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (request) {
|
||||
@@ -1339,6 +1332,7 @@ static void _dns_server_client_touch(struct dns_server_conn *client)
|
||||
static int _dns_server_client_close(struct dns_server_conn *client)
|
||||
{
|
||||
if (client->fd > 0) {
|
||||
epoll_ctl(server.epoll_fd, EPOLL_CTL_DEL, client->fd, NULL);
|
||||
close(client->fd);
|
||||
client->fd = -1;
|
||||
}
|
||||
@@ -1356,7 +1350,7 @@ static int _dns_server_accept(struct dns_server_conn *dnsserver, struct epoll_ev
|
||||
struct dns_server_conn *client = NULL;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
int fd = -1;
|
||||
|
||||
|
||||
fd = accept4(dnsserver->fd, (struct sockaddr *)&addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
@@ -1408,8 +1402,7 @@ int _dns_server_tcp_recv(struct dns_server_conn *dnsserver)
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = recv(dnsserver->fd, dnsserver->recvbuff.buf + dnsserver->recvbuff.size,
|
||||
sizeof(dnsserver->recvbuff.buf) - dnsserver->recvbuff.size, 0);
|
||||
len = recv(dnsserver->fd, dnsserver->recvbuff.buf + dnsserver->recvbuff.size, sizeof(dnsserver->recvbuff.buf) - dnsserver->recvbuff.size, 0);
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
return 1;
|
||||
@@ -1439,7 +1432,7 @@ int _dns_server_tcp_process_one_request(struct dns_server_conn *dnsserver)
|
||||
}
|
||||
|
||||
request_len = ntohs(*((unsigned short *)(dnsserver->recvbuff.buf + proceed_len)));
|
||||
|
||||
|
||||
if (request_len >= sizeof(dnsserver->recvbuff.buf)) {
|
||||
tlog(TLOG_ERROR, "request length is invalid.");
|
||||
return -1;
|
||||
@@ -1511,7 +1504,7 @@ int _dns_server_tcp_send(struct dns_server_conn *client)
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
} else if (len == 0 ) {
|
||||
} else if (len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1539,7 +1532,7 @@ static int _dns_server_process_tcp(struct dns_server_conn *dnsserver, struct epo
|
||||
if (_dns_server_tcp_process_requests(dnsserver) != 0) {
|
||||
_dns_server_client_close(dnsserver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event->events & EPOLLOUT) {
|
||||
if (_dns_server_tcp_send(dnsserver) != 0) {
|
||||
@@ -1638,7 +1631,6 @@ void _dns_server_tcp_idle_check(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _dns_server_period_run_second(void)
|
||||
{
|
||||
static unsigned int sec = 0;
|
||||
@@ -1721,6 +1713,7 @@ int dns_server_run(void)
|
||||
if (num == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct epoll_event *event = &events[i];
|
||||
struct dns_server_conn *dnsserver = event->data.ptr;
|
||||
@@ -1771,7 +1764,7 @@ int _dns_server_start_udp(void)
|
||||
if (server.udp_server.fd <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN;
|
||||
event.data.ptr = &server.udp_server;
|
||||
@@ -1790,7 +1783,7 @@ int _dns_server_start_tcp(void)
|
||||
if (server.tcp_server.fd <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN;
|
||||
event.data.ptr = &server.tcp_server;
|
||||
@@ -1816,7 +1809,6 @@ int dns_server_start(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int _dns_create_socket(const char *host_ip, int type)
|
||||
{
|
||||
int fd = -1;
|
||||
@@ -1896,7 +1888,6 @@ int _dns_server_socket(void)
|
||||
if (fd_tcp < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
server.udp_server.fd = fd_udp;
|
||||
|
||||
116
src/include/conf.h
Normal file
116
src/include/conf.h
Normal file
@@ -0,0 +1,116 @@
|
||||
#ifndef _GENERIC_CONF_H
|
||||
#define _GENERIC_CONF_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_LINE_LEN 1024
|
||||
#define MAX_KEY_LEN 64
|
||||
#define CONF_INT_MAX (~(1 << 31))
|
||||
#define CONF_INT_MIN (1 << 31)
|
||||
|
||||
struct config_item {
|
||||
const char *item;
|
||||
int (*item_func)(const char *item, void *data, int argc, char *argv[]);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct config_item_custom {
|
||||
void *custom_data;
|
||||
int (*custom_func)(void *data, int argc, char *argv[]);
|
||||
};
|
||||
|
||||
struct config_item_int {
|
||||
int *data;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
struct config_item_string {
|
||||
char *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct config_item_yesno {
|
||||
int *data;
|
||||
};
|
||||
|
||||
struct config_item_size {
|
||||
size_t *data;
|
||||
size_t min;
|
||||
size_t max;
|
||||
};
|
||||
|
||||
#define CONF_INT(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_int, &(struct config_item_int) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
#define CONF_STRING(key, value, len_value) \
|
||||
{ \
|
||||
key, conf_string, &(struct config_item_string) \
|
||||
{ \
|
||||
.data = value, .size = len_value \
|
||||
} \
|
||||
}
|
||||
#define CONF_YESNO(key, value) \
|
||||
{ \
|
||||
key, conf_yesno, &(struct config_item_yesno) \
|
||||
{ \
|
||||
.data = value \
|
||||
} \
|
||||
}
|
||||
#define CONF_SIZE(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_size, &(struct config_item_size) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
/*
|
||||
* func: int (*func)(void *data, int argc, char *argv[]);
|
||||
*/
|
||||
#define CONF_CUSTOM(key, func, data) \
|
||||
{ \
|
||||
key, conf_custom, &(struct config_item_custom) \
|
||||
{ \
|
||||
.custom_data = data, .custom_func = func \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CONF_END() \
|
||||
{ \
|
||||
0, 0, 0 \
|
||||
}
|
||||
|
||||
extern int conf_custom(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_int(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_string(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_yesno(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_size(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
* Example:
|
||||
* int num = 0;
|
||||
*
|
||||
* struct config_item itmes [] = {
|
||||
* CONF_INT("CONF_NUM", &num, -1, 10),
|
||||
* CONF_END();
|
||||
* }
|
||||
*
|
||||
* load_conf(file, items);
|
||||
*
|
||||
*/
|
||||
|
||||
int load_conf(const char *file, struct config_item items[]);
|
||||
|
||||
int load_conf_get_line_count(void);
|
||||
|
||||
void load_exit(void);
|
||||
|
||||
#endif // !_GENERIC_CONF_H
|
||||
263
src/lib/conf.c
Normal file
263
src/lib/conf.c
Normal file
@@ -0,0 +1,263 @@
|
||||
#include "conf.h"
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__thread int line_no;
|
||||
|
||||
int conf_custom(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_item_custom *item_custom = data;
|
||||
return item_custom->custom_func(item_custom->custom_data, argc, argv);
|
||||
}
|
||||
|
||||
int conf_int(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_item_int *item_int = data;
|
||||
int value = 0;
|
||||
if (argc < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = atoi(argv[1]);
|
||||
|
||||
if (value < item_int->min) {
|
||||
value = item_int->min;
|
||||
} else if (value > item_int->max) {
|
||||
value = item_int->max;
|
||||
}
|
||||
|
||||
*(item_int->data) = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_string(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_item_string *item_string = data;
|
||||
|
||||
if (argc < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(item_string->data, argv[1], item_string->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_yesno(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_item_yesno *item_yesno = data;
|
||||
int yes = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *value = argv[1];
|
||||
if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
|
||||
yes = 1;
|
||||
} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
|
||||
yes = 0;
|
||||
}
|
||||
|
||||
*(item_yesno->data) = yes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_size(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
/* read dns cache size */
|
||||
int base = 1;
|
||||
size_t size = 0;
|
||||
int num = 0;
|
||||
struct config_item_size *item_size = data;
|
||||
char *value = argv[1];
|
||||
|
||||
if (strstr(value, "k") || strstr(value, "K")) {
|
||||
base = 1024;
|
||||
} else if (strstr(value, "m") || strstr(value, "M")) {
|
||||
base = 1024 * 1024;
|
||||
} else if (strstr(value, "g") || strstr(value, "G")) {
|
||||
base = 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
num = atoi(value);
|
||||
if (num < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = num * base;
|
||||
if (size > item_size->max) {
|
||||
size = item_size->max;
|
||||
} else if (size < item_size->min) {
|
||||
size = item_size->min;
|
||||
}
|
||||
|
||||
*(item_size->data) = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void conf_getopt_reset(void)
|
||||
{
|
||||
static struct option long_options[] = {{"-", 0, 0, 0}, {0, 0, 0, 0}};
|
||||
int argc = 2;
|
||||
char *argv[3] = {"reset", "", 0};
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
getopt_long(argc, argv, "", long_options, NULL);
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
}
|
||||
|
||||
int conf_parse_args(char *key, char *value, int *argc, char **argv)
|
||||
{
|
||||
char *start = NULL;
|
||||
char *ptr = value;
|
||||
int count = 0;
|
||||
int sep_flag = ' ';
|
||||
|
||||
argv[0] = key;
|
||||
count++;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (*ptr == '\\') {
|
||||
char *tmp = ptr + 1;
|
||||
while (*tmp != '\0') {
|
||||
*(tmp - 1) = *tmp;
|
||||
tmp++;
|
||||
}
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*ptr == '"' && start == NULL) {
|
||||
sep_flag = '"';
|
||||
start = NULL;
|
||||
}
|
||||
|
||||
if (*ptr != sep_flag && start == NULL) {
|
||||
start = ptr;
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*ptr == sep_flag && start == NULL) {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*ptr == sep_flag && start) {
|
||||
argv[count] = start;
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
start = ptr;
|
||||
count++;
|
||||
sep_flag = ' ';
|
||||
start = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (start != ptr && start) {
|
||||
argv[count] = start;
|
||||
count++;
|
||||
}
|
||||
|
||||
*argc = count;
|
||||
argv[count + 1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_exit(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int load_conf_get_line_count(void)
|
||||
{
|
||||
return line_no;
|
||||
}
|
||||
|
||||
int load_conf_file(const char *file, struct config_item *items)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char line[MAX_LINE_LEN];
|
||||
char key[MAX_KEY_LEN];
|
||||
char value[MAX_LINE_LEN];
|
||||
int filed_num = 0;
|
||||
int i;
|
||||
int argc;
|
||||
char *argv[1024];
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
line_no = 0;
|
||||
while (fgets(line, MAX_LINE_LEN, fp)) {
|
||||
line_no++;
|
||||
filed_num = sscanf(line, "%63s %1023[^\r\n]s", key, value);
|
||||
if (filed_num <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* comment, skip */
|
||||
if (key[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if field format is not key = value, error */
|
||||
if (filed_num != 2) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for (i = 0;; i++) {
|
||||
if (items[i].item == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(items[i].item, key, MAX_KEY_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conf_parse_args(key, value, &argc, argv) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
conf_getopt_reset();
|
||||
/* call item function */
|
||||
if (items[i].item_func(items[i].item, items[i].data, argc, argv) != 0) {
|
||||
conf_getopt_reset();
|
||||
goto errout;
|
||||
}
|
||||
|
||||
conf_getopt_reset();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int load_conf(const char *file, struct config_item items[])
|
||||
{
|
||||
return load_conf_file(file, items);
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "art.h"
|
||||
#include "atomic.h"
|
||||
#include "conf.h"
|
||||
#include "dns_conf.h"
|
||||
#include "dns_client.h"
|
||||
#include "dns_server.h"
|
||||
#include "fast_ping.h"
|
||||
@@ -31,14 +31,14 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#define RESOLVE_FILE "/etc/resolv.conf"
|
||||
#define MAX_LINE_LEN 1024
|
||||
@@ -55,6 +55,7 @@ void help(void)
|
||||
" -f run forground.\n"
|
||||
" -c [conf] config file.\n"
|
||||
" -p [pid] pid file path\n"
|
||||
" -S ignore segment fault signal.\n"
|
||||
" -h show this help message.\n"
|
||||
|
||||
"Online help: http://pymumu.github.io/smartdns"
|
||||
@@ -119,7 +120,7 @@ int smartdns_add_servers(void)
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
for (i = 0; i < dns_conf_server_num; i++) {
|
||||
ret = dns_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type);
|
||||
ret = dns_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type, dns_conf_servers[i].result_flag);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "add server failed, %s:%d", dns_conf_servers[i].server, dns_conf_servers[i].port);
|
||||
return -1;
|
||||
@@ -206,7 +207,7 @@ int smartdns_init(void)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
//tlog_setlogscreen(1);
|
||||
//tlog_setlogscreen(1);
|
||||
tlog_setlevel(dns_conf_log_level);
|
||||
|
||||
if (smartdns_init_ssl() != 0) {
|
||||
@@ -262,7 +263,7 @@ void smartdns_exit(void)
|
||||
fast_ping_exit();
|
||||
smartdns_destroy_ssl();
|
||||
tlog_exit();
|
||||
load_exit();
|
||||
dns_server_load_exit();
|
||||
}
|
||||
|
||||
void sig_handle(int sig)
|
||||
@@ -287,11 +288,12 @@ int main(int argc, char *argv[])
|
||||
int opt;
|
||||
char config_file[MAX_LINE_LEN];
|
||||
char pid_file[MAX_LINE_LEN];
|
||||
int signal_ignore = 0;
|
||||
|
||||
strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
|
||||
strncpy(pid_file, SMARTDNS_PID_FILE, MAX_LINE_LEN);
|
||||
|
||||
while ((opt = getopt(argc, argv, "fhc:p:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "fhc:p:S")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
is_forground = 1;
|
||||
@@ -302,6 +304,9 @@ int main(int argc, char *argv[])
|
||||
case 'p':
|
||||
snprintf(pid_file, sizeof(pid_file), "%s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
signal_ignore = 1;
|
||||
break;
|
||||
case 'h':
|
||||
help();
|
||||
return 1;
|
||||
@@ -315,14 +320,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
signal(SIGABRT, sig_handle);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGBUS, sig_handle);
|
||||
signal(SIGSEGV, sig_handle);
|
||||
signal(SIGILL, sig_handle);
|
||||
signal(SIGFPE, sig_handle);
|
||||
if (signal_ignore == 0) {
|
||||
signal(SIGABRT, sig_handle);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGBUS, sig_handle);
|
||||
signal(SIGSEGV, sig_handle);
|
||||
signal(SIGILL, sig_handle);
|
||||
signal(SIGFPE, sig_handle);
|
||||
}
|
||||
|
||||
if (load_conf(config_file) != 0) {
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
}
|
||||
|
||||
if (create_pid_file(pid_file) != 0) {
|
||||
|
||||
@@ -155,6 +155,11 @@ int set_fd_nonblock(int fd, int nonblock)
|
||||
char *reverse_string(char *output, char *input, int len)
|
||||
{
|
||||
char *begin = output;
|
||||
if (len <= 0) {
|
||||
*output = 0;
|
||||
return output;
|
||||
}
|
||||
|
||||
len--;
|
||||
while (len >= 0) {
|
||||
*output = *(input + len);
|
||||
|
||||
@@ -20,4 +20,6 @@ int set_fd_nonblock(int fd, int nonblock);
|
||||
|
||||
char *reverse_string(char *output, char *input, int len);
|
||||
|
||||
void print_stack(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user