Feature: support local host name & ptr resolve.
This commit is contained in:
@@ -587,6 +587,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
|||||||
| force-AAAA-SOA | 强制 AAAA 地址返回 SOA | no | [yes\|no] | force-AAAA-SOA yes |
|
| force-AAAA-SOA | 强制 AAAA 地址返回 SOA | no | [yes\|no] | force-AAAA-SOA yes |
|
||||||
| force-qtype-SOA | 强制指定 qtype 返回 SOA | qtype id | [<qtypeid> \| ...] | force-qtype-SOA 65 28
|
| force-qtype-SOA | 强制指定 qtype 返回 SOA | qtype id | [<qtypeid> \| ...] | force-qtype-SOA 65 28
|
||||||
| prefetch-domain | 域名预先获取功能 | no | [yes\|no] | prefetch-domain yes |
|
| prefetch-domain | 域名预先获取功能 | no | [yes\|no] | prefetch-domain yes |
|
||||||
|
| dnsmasq-lease-file | 支持读取dnsmasq dhcp文件解析本地主机名功能 | 无 | dnsmasq dhcp lease文件路径 | dnsmasq-lease-file /var/lib/misc/dnsmasq.leases |
|
||||||
| serve-expired | 过期缓存服务功能 | yes | [yes\|no],开启此功能后,如果有请求时尝试回应 TTL 为 0 的过期记录,并发查询记录,以避免查询等待 |
|
| serve-expired | 过期缓存服务功能 | yes | [yes\|no],开启此功能后,如果有请求时尝试回应 TTL 为 0 的过期记录,并发查询记录,以避免查询等待 |
|
||||||
| serve-expired-ttl | 过期缓存服务最长超时时间 | 0 | 秒,0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-ttl 0 |
|
| serve-expired-ttl | 过期缓存服务最长超时时间 | 0 | 秒,0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-ttl 0 |
|
||||||
| serve-expired-reply-ttl | 回应的过期缓存 TTL | 5 | 秒,0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-reply-ttl 30 |
|
| serve-expired-reply-ttl | 回应的过期缓存 TTL | 5 | 秒,0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-reply-ttl 30 |
|
||||||
|
|||||||
@@ -531,6 +531,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
|||||||
|force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes
|
|force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes
|
||||||
|force-qtype-SOA|force specific qtype return SOA|qtype id|[qtypeid | ...]|force-qtype-SOA 65 28
|
|force-qtype-SOA|force specific qtype return SOA|qtype id|[qtypeid | ...]|force-qtype-SOA 65 28
|
||||||
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|
||||||
|
|dnsmasq-lease-file|Support reading dnsmasq dhcp file to resolve local hostname|None|dnsmasq dhcp lease file| dnsmasq-lease-file /var/lib/misc/dnsmasq.leases
|
||||||
|serve-expired|Cache serve expired feature|yes|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|
|serve-expired|Cache serve expired feature|yes|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|
||||||
|serve-expired-ttl|Cache serve expired limite TTL|0|second,0:disable,> 0 seconds after expiration|serve-expired-ttl 0
|
|serve-expired-ttl|Cache serve expired limite TTL|0|second,0:disable,> 0 seconds after expiration|serve-expired-ttl 0
|
||||||
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second,0:disable,> 0 seconds after expiration|serve-expired-reply-ttl 30
|
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second,0:disable,> 0 seconds after expiration|serve-expired-reply-ttl 30
|
||||||
|
|||||||
358
src/dns_conf.c
358
src/dns_conf.c
@@ -28,6 +28,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define DEFAULT_DNS_CACHE_SIZE 512
|
#define DEFAULT_DNS_CACHE_SIZE 512
|
||||||
|
|
||||||
@@ -42,6 +43,14 @@ struct dns_qtype_soa_table dns_qtype_soa_table;
|
|||||||
/* dns groups */
|
/* dns groups */
|
||||||
struct dns_group_table dns_group_table;
|
struct dns_group_table dns_group_table;
|
||||||
|
|
||||||
|
struct dns_ptr_table dns_ptr_table;
|
||||||
|
|
||||||
|
char dns_conf_dnsmasq_lease_file[DNS_MAX_PATH];
|
||||||
|
time_t dns_conf_dnsmasq_lease_file_time;
|
||||||
|
|
||||||
|
struct dns_hosts_table dns_hosts_table;
|
||||||
|
int dns_hosts_record_num;
|
||||||
|
|
||||||
/* server ip/port */
|
/* server ip/port */
|
||||||
struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
|
struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
|
||||||
int dns_conf_bind_ip_num = 0;
|
int dns_conf_bind_ip_num = 0;
|
||||||
@@ -1429,6 +1438,342 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dns_ptr *_dns_conf_get_ptr(const char *ptr_domain)
|
||||||
|
{
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct dns_ptr *ptr = NULL;
|
||||||
|
|
||||||
|
key = hash_string(ptr_domain);
|
||||||
|
hash_for_each_possible(dns_ptr_table.ptr, ptr, node, key)
|
||||||
|
{
|
||||||
|
if (strncmp(ptr->ptr_domain, ptr_domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = malloc(sizeof(*ptr));
|
||||||
|
if (ptr == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_strncpy(ptr->ptr_domain, ptr_domain, DNS_MAX_PTR_LEN);
|
||||||
|
hash_add(dns_ptr_table.ptr, &ptr->node, key);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
errout:
|
||||||
|
if (ptr) {
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_ptr_add(const char *hostname, const char *ip)
|
||||||
|
{
|
||||||
|
struct dns_ptr *ptr = NULL;
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
unsigned char *paddr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
char ptr_domain[DNS_MAX_PTR_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;
|
||||||
|
paddr = (unsigned char *)&(addr_in->sin_addr.s_addr);
|
||||||
|
snprintf(ptr_domain, sizeof(ptr_domain), "%d.%d.%d.%d.in-addr.arpa",
|
||||||
|
paddr[3], paddr[2], paddr[1], paddr[0]);
|
||||||
|
} break;
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *addr_in6;
|
||||||
|
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||||
|
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||||
|
paddr = addr_in6->sin6_addr.s6_addr + 12;
|
||||||
|
snprintf(ptr_domain, sizeof(ptr_domain), "%d.%d.%d.%d.in-addr.arpa",
|
||||||
|
paddr[3], paddr[2], paddr[1], paddr[0]);
|
||||||
|
} else {
|
||||||
|
paddr = addr_in6->sin6_addr.s6_addr;
|
||||||
|
snprintf(
|
||||||
|
ptr_domain, sizeof(ptr_domain),
|
||||||
|
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||||||
|
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||||||
|
"%x.ip6.arpa",
|
||||||
|
paddr[15] & 0xF, (paddr[15] >> 4) & 0xF, paddr[14] & 0xF,
|
||||||
|
(paddr[14] >> 4) & 0xF, paddr[13] & 0xF, (paddr[13] >> 4) & 0xF,
|
||||||
|
paddr[12] & 0xF, (paddr[12] >> 4) & 0xF, paddr[11] & 0xF,
|
||||||
|
(paddr[11] >> 4) & 0xF, paddr[10] & 0xF, (paddr[10] >> 4) & 0xF,
|
||||||
|
paddr[9] & 0xF, (paddr[9] >> 4) & 0xF, paddr[8] & 0xF,
|
||||||
|
(paddr[8] >> 4) & 0xF, paddr[7] & 0xF, (paddr[7] >> 4) & 0xF,
|
||||||
|
paddr[6] & 0xF, (paddr[6] >> 4) & 0xF, paddr[5] & 0xF,
|
||||||
|
(paddr[5] >> 4) & 0xF, paddr[4] & 0xF, (paddr[4] >> 4) & 0xF,
|
||||||
|
paddr[3] & 0xF, (paddr[3] >> 4) & 0xF, paddr[2] & 0xF,
|
||||||
|
(paddr[2] >> 4) & 0xF, paddr[1] & 0xF, (paddr[1] >> 4) & 0xF,
|
||||||
|
paddr[0] & 0xF, (paddr[0] >> 4) & 0xF);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
goto errout;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = _dns_conf_get_ptr(ptr_domain);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_strncpy(ptr->hostname, hostname, DNS_MAX_CNAME_LEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _config_ptr_table_destroy(void)
|
||||||
|
{
|
||||||
|
struct dns_ptr *ptr = NULL;
|
||||||
|
struct hlist_node *tmp = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
hash_for_each_safe(dns_ptr_table.ptr, i, tmp, ptr, node)
|
||||||
|
{
|
||||||
|
hlist_del_init(&ptr->node);
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dns_hosts *_dns_conf_get_hosts(const char *hostname, int dns_type)
|
||||||
|
{
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct dns_hosts *host = NULL;
|
||||||
|
char hostname_lower[DNS_MAX_CNAME_LEN];
|
||||||
|
|
||||||
|
key = hash_string(to_lower_case(hostname_lower, hostname, DNS_MAX_CNAME_LEN));
|
||||||
|
key = jhash(&dns_type, sizeof(dns_type), key);
|
||||||
|
hash_for_each_possible(dns_hosts_table.hosts, host, node, key)
|
||||||
|
{
|
||||||
|
if (host->dns_type != dns_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(host->domain, hostname_lower, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = malloc(sizeof(*host));
|
||||||
|
if (host == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_strncpy(host->domain, hostname_lower, DNS_MAX_CNAME_LEN);
|
||||||
|
host->dns_type = dns_type;
|
||||||
|
host->is_soa = 1;
|
||||||
|
hash_add(dns_hosts_table.hosts, &host->node, key);
|
||||||
|
|
||||||
|
return host;
|
||||||
|
errout:
|
||||||
|
if (host) {
|
||||||
|
free(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_host_add(const char *hostname, const char *ip, dns_hosts_type host_type)
|
||||||
|
{
|
||||||
|
struct dns_hosts *host = NULL;
|
||||||
|
struct dns_hosts *host_other __attribute__((unused));;
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
int dns_type = 0;
|
||||||
|
int dns_type_other = 0;
|
||||||
|
|
||||||
|
if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (addr.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
dns_type = DNS_T_A;
|
||||||
|
dns_type_other = DNS_T_AAAA;
|
||||||
|
break;
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *addr_in6;
|
||||||
|
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||||
|
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||||
|
dns_type = DNS_T_A;
|
||||||
|
dns_type_other = DNS_T_AAAA;
|
||||||
|
} else {
|
||||||
|
dns_type = DNS_T_AAAA;
|
||||||
|
dns_type_other = DNS_T_A;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
goto errout;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = _dns_conf_get_hosts(hostname, dns_type);
|
||||||
|
if (host == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add this to return SOA when addr is not exist */
|
||||||
|
host_other = _dns_conf_get_hosts(hostname, dns_type_other);
|
||||||
|
|
||||||
|
host->host_type = host_type;
|
||||||
|
|
||||||
|
switch (addr.ss_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *addr_in;
|
||||||
|
addr_in = (struct sockaddr_in *)&addr;
|
||||||
|
memcpy(host->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||||
|
host->is_soa = 0;
|
||||||
|
} 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(host->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||||
|
} else {
|
||||||
|
memcpy(host->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||||
|
}
|
||||||
|
host->is_soa = 0;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_hosts_record_num++;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_dhcp_lease_dnsmasq_add(const char *file)
|
||||||
|
{
|
||||||
|
FILE *fp = NULL;
|
||||||
|
char line[MAX_LINE_LEN];
|
||||||
|
char ip[DNS_MAX_IPLEN];
|
||||||
|
char hostname[DNS_MAX_CNAME_LEN];
|
||||||
|
int ret = 0;
|
||||||
|
int line_no = 0;
|
||||||
|
int filed_num;
|
||||||
|
|
||||||
|
fp = fopen(file, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
tlog(TLOG_WARN, "open file %s error, %s", file, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_no = 0;
|
||||||
|
while (fgets(line, MAX_LINE_LEN, fp)) {
|
||||||
|
line_no++;
|
||||||
|
filed_num = sscanf(line, "%*s %*s %64s %256s %*s", ip, hostname);
|
||||||
|
if (filed_num <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(hostname, "*", DNS_MAX_CNAME_LEN) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _conf_host_add(hostname, ip, DNS_HOST_TYPE_DNSMASQ);
|
||||||
|
if (ret != 0) {
|
||||||
|
tlog(TLOG_WARN, "add host %s/%s at %d failed", hostname, ip, line_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _conf_ptr_add(hostname, ip);
|
||||||
|
if (ret != 0) {
|
||||||
|
tlog(TLOG_WARN, "add ptr %s/%s at %d failed.", hostname, ip, line_no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_dhcp_lease_dnsmasq_file(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_strncpy(dns_conf_dnsmasq_lease_file, argv[1], DNS_MAX_PATH);
|
||||||
|
if (_conf_dhcp_lease_dnsmasq_add(argv[1]) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(dns_conf_dnsmasq_lease_file, &statbuf) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_conf_dnsmasq_lease_file_time = statbuf.st_mtime;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_hosts_file(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _config_host_table_destroy(void)
|
||||||
|
{
|
||||||
|
struct dns_hosts *host = NULL;
|
||||||
|
struct hlist_node *tmp = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
hash_for_each_safe(dns_hosts_table.hosts, i, tmp, host, node)
|
||||||
|
{
|
||||||
|
hlist_del_init(&host->node);
|
||||||
|
free(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_hosts_record_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_server_check_update_hosts(void)
|
||||||
|
{
|
||||||
|
struct stat statbuf;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (stat(dns_conf_dnsmasq_lease_file, &statbuf) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dns_conf_dnsmasq_lease_file_time == statbuf.st_mtime) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
if (now - statbuf.st_mtime < 30) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_config_ptr_table_destroy();
|
||||||
|
_config_host_table_destroy();
|
||||||
|
|
||||||
|
if (_conf_dhcp_lease_dnsmasq_add(dns_conf_dnsmasq_lease_file) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_conf_dnsmasq_lease_file_time = statbuf.st_mtime;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int _config_log_level(void *data, int argc, char *argv[])
|
static int _config_log_level(void *data, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
/* read log level and set */
|
/* read log level and set */
|
||||||
@@ -1497,6 +1842,8 @@ static struct config_item _config_item[] = {
|
|||||||
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
|
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
|
||||||
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
|
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
|
||||||
CONF_CUSTOM("domain-rules", _conf_domain_rules, NULL),
|
CONF_CUSTOM("domain-rules", _conf_domain_rules, NULL),
|
||||||
|
CONF_CUSTOM("dnsmasq-lease-file", _conf_dhcp_lease_dnsmasq_file, NULL),
|
||||||
|
CONF_CUSTOM("hosts-file", _conf_hosts_file, NULL),
|
||||||
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
|
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
|
||||||
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
|
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
|
||||||
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
||||||
@@ -1520,10 +1867,15 @@ static int _conf_printf(const char *file, int lineno, int ret)
|
|||||||
|
|
||||||
int config_addtional_file(void *data, int argc, char *argv[])
|
int config_addtional_file(void *data, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *conf_file = argv[1];
|
char *conf_file;
|
||||||
char file_path[DNS_MAX_PATH];
|
char file_path[DNS_MAX_PATH];
|
||||||
char file_path_dir[DNS_MAX_PATH];
|
char file_path_dir[DNS_MAX_PATH];
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf_file = argv[1];
|
||||||
if (conf_file[0] != '/') {
|
if (conf_file[0] != '/') {
|
||||||
safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH);
|
safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH);
|
||||||
dirname(file_path_dir);
|
dirname(file_path_dir);
|
||||||
@@ -1563,6 +1915,8 @@ static int _dns_server_load_conf_init(void)
|
|||||||
hash_init(dns_ipset_table.ipset);
|
hash_init(dns_ipset_table.ipset);
|
||||||
hash_init(dns_qtype_soa_table.qtype);
|
hash_init(dns_qtype_soa_table.qtype);
|
||||||
hash_init(dns_group_table.group);
|
hash_init(dns_group_table.group);
|
||||||
|
hash_init(dns_hosts_table.hosts);
|
||||||
|
hash_init(dns_ptr_table.ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1574,6 +1928,8 @@ void dns_server_load_exit(void)
|
|||||||
Destroy_Radix(dns_conf_address_rule.ipv6, _config_address_destroy, NULL);
|
Destroy_Radix(dns_conf_address_rule.ipv6, _config_address_destroy, NULL);
|
||||||
_config_ipset_table_destroy();
|
_config_ipset_table_destroy();
|
||||||
_config_group_table_destroy();
|
_config_group_table_destroy();
|
||||||
|
_config_ptr_table_destroy();
|
||||||
|
_config_host_table_destroy();
|
||||||
_config_qtype_soa_table_destroy();
|
_config_qtype_soa_table_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ extern "C" {
|
|||||||
#define DNS_MAX_BIND_IP 16
|
#define DNS_MAX_BIND_IP 16
|
||||||
#define DNS_MAX_SERVERS 64
|
#define DNS_MAX_SERVERS 64
|
||||||
#define DNS_MAX_SERVER_NAME_LEN 128
|
#define DNS_MAX_SERVER_NAME_LEN 128
|
||||||
|
#define DNS_MAX_PTR_LEN 128
|
||||||
#define DNS_MAX_IPSET_NAMELEN 32
|
#define DNS_MAX_IPSET_NAMELEN 32
|
||||||
#define DNS_GROUP_NAME_LEN 32
|
#define DNS_GROUP_NAME_LEN 32
|
||||||
#define DNS_NAX_GROUP_NUMBER 16
|
#define DNS_NAX_GROUP_NUMBER 16
|
||||||
@@ -145,6 +146,40 @@ struct dns_group_table {
|
|||||||
};
|
};
|
||||||
extern struct dns_group_table dns_group_table;
|
extern struct dns_group_table dns_group_table;
|
||||||
|
|
||||||
|
struct dns_ptr {
|
||||||
|
struct hlist_node node;
|
||||||
|
char ptr_domain[DNS_MAX_PTR_LEN];
|
||||||
|
char hostname[DNS_MAX_CNAME_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_ptr_table {
|
||||||
|
DECLARE_HASHTABLE(ptr, 16);
|
||||||
|
};
|
||||||
|
extern struct dns_ptr_table dns_ptr_table;
|
||||||
|
|
||||||
|
typedef enum dns_hosts_type {
|
||||||
|
DNS_HOST_TYPE_HOST = 0,
|
||||||
|
DNS_HOST_TYPE_DNSMASQ = 1,
|
||||||
|
} dns_hosts_type;
|
||||||
|
|
||||||
|
struct dns_hosts {
|
||||||
|
struct hlist_node node;
|
||||||
|
char domain[DNS_MAX_CNAME_LEN];
|
||||||
|
dns_hosts_type host_type;
|
||||||
|
int dns_type;
|
||||||
|
int is_soa;
|
||||||
|
union {
|
||||||
|
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||||
|
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_hosts_table {
|
||||||
|
DECLARE_HASHTABLE(hosts, 16);
|
||||||
|
};
|
||||||
|
extern struct dns_hosts_table dns_hosts_table;
|
||||||
|
extern int dns_hosts_record_num;
|
||||||
|
|
||||||
struct dns_servers {
|
struct dns_servers {
|
||||||
char server[DNS_MAX_IPLEN];
|
char server[DNS_MAX_IPLEN];
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
@@ -270,6 +305,8 @@ void dns_server_load_exit(void);
|
|||||||
|
|
||||||
int dns_server_load_conf(const char *file);
|
int dns_server_load_conf(const char *file);
|
||||||
|
|
||||||
|
int dns_server_check_update_hosts(void);
|
||||||
|
|
||||||
extern int config_addtional_file(void *data, int argc, char *argv[]);
|
extern int config_addtional_file(void *data, int argc, char *argv[]);
|
||||||
#ifdef __cpluscplus
|
#ifdef __cpluscplus
|
||||||
}
|
}
|
||||||
|
|||||||
195
src/dns_server.c
195
src/dns_server.c
@@ -192,6 +192,7 @@ 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;
|
||||||
|
char ptr_hostname[DNS_MAX_CNAME_LEN];
|
||||||
|
|
||||||
int has_cname;
|
int has_cname;
|
||||||
char cname[DNS_MAX_CNAME_LEN];
|
char cname[DNS_MAX_CNAME_LEN];
|
||||||
@@ -639,32 +640,7 @@ static int _dns_add_rrs(struct dns_server_post_context *context)
|
|||||||
char *domain = request->domain;
|
char *domain = request->domain;
|
||||||
if (request->has_ptr) {
|
if (request->has_ptr) {
|
||||||
/* add PTR record */
|
/* add PTR record */
|
||||||
char hostname[DNS_MAX_CNAME_LEN];
|
ret = dns_add_PTR(context->packet, DNS_RRS_AN, request->domain, 30, request->ptr_hostname);
|
||||||
if (dns_conf_server_name[0] == 0) {
|
|
||||||
/* get local host name */
|
|
||||||
if (getdomainname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
|
||||||
if (gethostname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get host name again */
|
|
||||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN) == 0) {
|
|
||||||
if (gethostname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if hostname is (none), return smartdns */
|
|
||||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN) == 0) {
|
|
||||||
safe_strncpy(hostname, "smartdns", DNS_MAX_CNAME_LEN);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* return configured server name */
|
|
||||||
safe_strncpy(hostname, dns_conf_server_name, DNS_MAX_CNAME_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dns_add_PTR(context->packet, DNS_RRS_AN, request->domain, 30, hostname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add CNAME record */
|
/* add CNAME record */
|
||||||
@@ -2478,7 +2454,35 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _dns_server_process_ptr(struct dns_request *request)
|
|
||||||
|
static int _dns_server_process_ptrs(struct dns_request *request)
|
||||||
|
{
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct dns_ptr *ptr = NULL;
|
||||||
|
struct dns_ptr *ptr_tmp = NULL;
|
||||||
|
key = hash_string(request->domain);
|
||||||
|
hash_for_each_possible(dns_ptr_table.ptr, ptr_tmp, node, key)
|
||||||
|
{
|
||||||
|
if (strncmp(ptr_tmp->ptr_domain, request->domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = ptr_tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
request->has_ptr = 1;
|
||||||
|
safe_strncpy(request->ptr_hostname, ptr->hostname, DNS_MAX_CNAME_LEN);
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dns_server_process_local_ptr(struct dns_request *request)
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifaddr = NULL;
|
struct ifaddrs *ifaddr = NULL;
|
||||||
struct ifaddrs *ifa = NULL;
|
struct ifaddrs *ifa = NULL;
|
||||||
@@ -2530,19 +2534,21 @@ static int _dns_server_process_ptr(struct dns_request *request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(request->domain, reverse_addr) != NULL) {
|
if (strncmp(request->domain, reverse_addr, DNS_MAX_CNAME_LEN) == 0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine if the smartdns service is in effect. */
|
/* Determine if the smartdns service is in effect. */
|
||||||
if (strstr(request->domain, "0.0.0.0.in-addr.arpa") != NULL) {
|
if (strncmp(request->domain, "0.0.0.0.in-addr.arpa", DNS_MAX_CNAME_LEN) ==
|
||||||
|
0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine if the smartdns service is in effect. */
|
/* Determine if the smartdns service is in effect. */
|
||||||
if (found == 0 && strncmp(request->domain, "smartdns", sizeof("smartdns")) == 0) {
|
if (found == 0 &&
|
||||||
|
strncmp(request->domain, "smartdns", sizeof("smartdns")) == 0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2550,13 +2556,33 @@ static int _dns_server_process_ptr(struct dns_request *request)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
request->rcode = DNS_RC_NOERROR;
|
char hostname[DNS_MAX_CNAME_LEN];
|
||||||
|
if (dns_conf_server_name[0] == 0) {
|
||||||
|
/* get local host name */
|
||||||
|
if (getdomainname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
if (gethostname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get host name again */
|
||||||
|
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN) == 0) {
|
||||||
|
if (gethostname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if hostname is (none), return smartdns */
|
||||||
|
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN) == 0) {
|
||||||
|
safe_strncpy(hostname, "smartdns", DNS_MAX_CNAME_LEN);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* return configured server name */
|
||||||
|
safe_strncpy(hostname, dns_conf_server_name, DNS_MAX_CNAME_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
request->has_ptr = 1;
|
request->has_ptr = 1;
|
||||||
struct dns_server_post_context context;
|
safe_strncpy(request->ptr_hostname, hostname, DNS_MAX_CNAME_LEN);
|
||||||
_dns_server_post_context_init(&context, request);
|
|
||||||
context.do_reply = 1;
|
|
||||||
context.do_audit = 0;
|
|
||||||
_dns_request_post(&context);
|
|
||||||
|
|
||||||
freeifaddrs(ifaddr);
|
freeifaddrs(ifaddr);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2567,6 +2593,28 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_server_process_ptr(struct dns_request *request)
|
||||||
|
{
|
||||||
|
if (_dns_server_process_ptrs(request) == 0) {
|
||||||
|
goto reply_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dns_server_process_local_ptr(request) == 0) {
|
||||||
|
goto reply_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
reply_exit:
|
||||||
|
request->rcode = DNS_RC_NOERROR;
|
||||||
|
struct dns_server_post_context context;
|
||||||
|
_dns_server_post_context_init(&context, request);
|
||||||
|
context.do_reply = 1;
|
||||||
|
context.do_audit = 0;
|
||||||
|
_dns_request_post(&context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void _dns_server_log_rule(const char *domain, enum domain_rule rule_type, unsigned char *rule_key,
|
static void _dns_server_log_rule(const char *domain, enum domain_rule rule_type, unsigned char *rule_key,
|
||||||
int rule_key_len)
|
int rule_key_len)
|
||||||
{
|
{
|
||||||
@@ -3199,6 +3247,71 @@ static void _dns_server_check_set_passthrough(struct dns_request *request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_server_process_host(struct dns_request *request)
|
||||||
|
{
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct dns_hosts *host = NULL;
|
||||||
|
struct dns_hosts *host_tmp = NULL;
|
||||||
|
int dns_type = request->qtype;
|
||||||
|
char hostname_lower[DNS_MAX_CNAME_LEN];
|
||||||
|
|
||||||
|
if (dns_hosts_record_num <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = hash_string(to_lower_case(hostname_lower, request->domain, DNS_MAX_CNAME_LEN));
|
||||||
|
key = jhash(&dns_type, sizeof(dns_type), key);
|
||||||
|
hash_for_each_possible(dns_hosts_table.hosts, host_tmp, node, key)
|
||||||
|
{
|
||||||
|
if (host_tmp->dns_type != dns_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(host_tmp->domain, hostname_lower, DNS_MAX_CNAME_LEN) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = host_tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host->is_soa) {
|
||||||
|
request->has_soa = 1;
|
||||||
|
return _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (request->qtype) {
|
||||||
|
case DNS_T_A:
|
||||||
|
memcpy(request->ipv4_addr, host->ipv4_addr, DNS_RR_A_LEN);
|
||||||
|
request->ttl_v4 = 600;
|
||||||
|
request->has_ipv4 = 1;
|
||||||
|
break;
|
||||||
|
case DNS_T_AAAA:
|
||||||
|
memcpy(request->ipv6_addr, host->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||||
|
request->ttl_v6 = 600;
|
||||||
|
request->has_ipv6 = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto errout;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
request->rcode = DNS_RC_NOERROR;
|
||||||
|
struct dns_server_post_context context;
|
||||||
|
_dns_server_post_context_init(&context, request);
|
||||||
|
context.do_reply = 1;
|
||||||
|
context.do_audit = 1;
|
||||||
|
_dns_request_post(&context);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_server_do_query(struct dns_request *request, const char *domain, int qtype)
|
static int _dns_server_do_query(struct dns_request *request, const char *domain, int qtype)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@@ -3219,6 +3332,10 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
|
|||||||
group_name = dns_group;
|
group_name = dns_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_dns_server_process_host(request) == 0) {
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
_dns_server_set_dualstack_selection(request);
|
_dns_server_set_dualstack_selection(request);
|
||||||
|
|
||||||
if (_dns_server_process_special_query(request) == 0) {
|
if (_dns_server_process_special_query(request) == 0) {
|
||||||
@@ -3873,6 +3990,12 @@ static void _dns_server_period_run_second(void)
|
|||||||
if (sec % IPV6_READY_CHECK_TIME == 0 && is_ipv6_ready == 0) {
|
if (sec % IPV6_READY_CHECK_TIME == 0 && is_ipv6_ready == 0) {
|
||||||
_dns_server_check_ipv6_ready();
|
_dns_server_check_ipv6_ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sec % 60 == 0) {
|
||||||
|
if (dns_server_check_update_hosts() == 0) {
|
||||||
|
tlog(TLOG_INFO, "Update host file data");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_server_period_run(void)
|
static void _dns_server_period_run(void)
|
||||||
|
|||||||
27
src/util.c
27
src/util.c
@@ -133,7 +133,7 @@ errout:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len)
|
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len)
|
||||||
{
|
{
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *result = NULL;
|
struct addrinfo *result = NULL;
|
||||||
@@ -473,6 +473,31 @@ char *reverse_string(char *output, const char *input, int len, int to_lower_case
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *to_lower_case(char *output, const char *input, int len)
|
||||||
|
{
|
||||||
|
char *begin = output;
|
||||||
|
int i = 0;
|
||||||
|
if (len <= 0) {
|
||||||
|
*output = 0;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
len--;
|
||||||
|
while (i < len && *(input + i) != '\0') {
|
||||||
|
*output = *(input + i);
|
||||||
|
if (*output >= 'A' && *output <= 'Z') {
|
||||||
|
/* To lower case */
|
||||||
|
*output = *output + 32;
|
||||||
|
}
|
||||||
|
output++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = 0;
|
||||||
|
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void _ipset_add_attr(struct nlmsghdr *netlink_head, uint16_t type, size_t len, const void *data)
|
static inline void _ipset_add_attr(struct nlmsghdr *netlink_head, uint16_t type, size_t len, const void *data)
|
||||||
{
|
{
|
||||||
struct ipset_netlink_attr *attr = (void *)netlink_head + NETLINK_ALIGN(netlink_head->nlmsg_len);
|
struct ipset_netlink_attr *attr = (void *)netlink_head + NETLINK_ALIGN(netlink_head->nlmsg_len);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ unsigned long get_tick_count(void);
|
|||||||
|
|
||||||
char *gethost_by_addr(char *host, int maxsize, struct sockaddr *addr);
|
char *gethost_by_addr(char *host, int maxsize, struct sockaddr *addr);
|
||||||
|
|
||||||
int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len);
|
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len);
|
||||||
|
|
||||||
int getsocknet_inet(int fd, struct sockaddr *addr, socklen_t *addr_len);
|
int getsocknet_inet(int fd, struct sockaddr *addr, socklen_t *addr_len);
|
||||||
|
|
||||||
@@ -65,6 +65,8 @@ int set_fd_nonblock(int fd, int nonblock);
|
|||||||
|
|
||||||
char *reverse_string(char *output, const char *input, int len, int to_lower_case);
|
char *reverse_string(char *output, const char *input, int len, int to_lower_case);
|
||||||
|
|
||||||
|
char *to_lower_case(char *output, const char *input, int len);
|
||||||
|
|
||||||
void print_stack(void);
|
void print_stack(void);
|
||||||
|
|
||||||
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout);
|
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout);
|
||||||
|
|||||||
Reference in New Issue
Block a user