nftset: Remove libnftable dependency

This commit is contained in:
Nick Peng
2022-11-15 22:31:34 +08:00
parent 934701941b
commit 85d011eae8
12 changed files with 456 additions and 105 deletions

View File

@@ -545,10 +545,11 @@ entware|ipkg update</br>ipkg install smartdns|软件源路径https://bin.entw
| address | 指定域名 IP 地址 | 无 | address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6] <br>- 表示忽略 <br># 表示返回 SOA <br>4 表示 IPv4 <br>6 表示 IPv6 | address /www.example.com/1.2.3.4 |
| nameserver | 指定域名使用 server 组解析 | 无 | nameserver /domain/[group\|-], group 为组名,- 表示忽略此规则,配套 server 中的 -group 参数使用 | nameserver /www.example.com/office |
| ipset | 域名 ipset | 无 | ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]]-表示忽略 | ipset /www.example.com/#4:dns4,#6:- |
| ipset-timeout | 设置 ipset 超时功能启用 | 自动 | [yes] | ipset-timeout yes |
| ipset-timeout | 设置 ipset 超时功能启用 | no | [yes\|no] | ipset-timeout yes |
| nftset | 域名 nftset | 无 | nftset /domain/#[4\|6]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]]-表示忽略ipv4 地址的 family 只支持 inet 和 ipipv6 地址的 family 只支持 inet 和 ip6由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset /www.example.com/#4:inet#mytab#dns4,#6:- |
| nftset-timeout | 设置 nftset 超时功能启用 | 自动 | [yes] | nftset-timeout yes |
| domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br>[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br>[-a\|-address]:参考 address 配置<br>[-n\|-nameserver]:参考 nameserver 配置<br>[-p\|-ipset]参考ipset配置<br>[-s\|-nftset]参考nftset配置<br>[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection | domain-rules /www.example.com/ -speed-check-mode none |
| nftset-timeout | 设置 nftset 超时功能启用 | no | [yes\|no] | nftset-timeout yes |
| nftset-debug | 设置 nftset 调试功能启用 | no | [yes\|no] | nftset-debug yes |
| domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br>[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br>[-a\|-address]:参考 address 配置<br>[-n\|-nameserver]:参考 nameserver 配置<br>[-p\|-ipset]参考ipset配置<br>[-t\|-nftset]参考nftset配置<br>[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection | domain-rules /www.example.com/ -speed-check-mode none |
| domain-set | 设置域名集合 | 无 | domain-set [options...]<br>[-n\|-name]:域名集合名称 <br>[-t\|-type]域名集合类型当前仅支持list格式为域名列表一行一个域名。<br>[-f\|-file]:域名集合文件路径。<br> 选项需要配合address, nameserver, ipset, nftset等需要指定域名的地方使用使用方式为 /domain-set:[name]/| domain-set -name set -type list -file /path/to/list <br> address /domain-set:set/1.2.4.8 |
| bogus-nxdomain | 假冒 IP 地址过滤 | 无 | [ip/subnet],可重复 | bogus-nxdomain 1.2.3.4/16 |
| ignore-ip | 忽略 IP 地址 | 无 | [ip/subnet],可重复 | ignore-ip 1.2.3.4/16 |

View File

@@ -504,10 +504,11 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4
|nameserver|To query domain with specific server group|None|nameserver /domain/[group\|-], `group` is the group name, `-` means ignore this rule, use the `-group` parameter in the related server|nameserver /www.example.com/office
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:-
|ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes
|ipset-timeout|ipset timeout enable|no|[yes\|no]|ipset-timeout yes
|nftset|Domain nftset|None|nftset /domain/#[4\|6]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]], `-` to ignore; the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses; due to the limitation of nft, two types of addresses have to be stored in two sets|nftset /www.example.com/#4:inet#mytab#dns4,#6:-
|nftset-timeout|nftset timeout enable|auto|[yes]|nftset-timeout yes
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: set speed check modesame as parameter `speed-check-mode`<br>`[-a\|-address]`: same as parameter `address` <br>`[-n\|-nameserver]`: same as parameter `nameserver`<br>`[-p\|-ipset]`: same as parameter `nftset`<br>`[-s\|-nftset]`: same as parameter `nftset`<br>`[-d\|-dualstack-ip-selection]`: same as parameter `dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none
|nftset-timeout|nftset timeout enable|no|[yes\|no]|nftset-timeout yes
|nftset-debug|nftset debug enable|no|[yes\|no]|nftset-debug yes
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: set speed check modesame as parameter `speed-check-mode`<br>`[-a\|-address]`: same as parameter `address` <br>`[-n\|-nameserver]`: same as parameter `nameserver`<br>`[-p\|-ipset]`: same as parameter `nftset`<br>`[-t\|-nftset]`: same as parameter `nftset`<br>`[-d\|-dualstack-ip-selection]`: same as parameter `dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none
| domain-set | collection of domains|None| domain-set [options...]<br>[-n\|-name]name of set <br>[-t\|-type] [list]: set type, only support list, one domain per line <br>[-f\|-file]file path of domain set<br> used with address, nameserver, ipset, nftset, example: /domain-set:[name]/ | domain-set -name set -type list -file /path/to/list <br> address /domain-set:set/1.2.4.8 |
|bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16
|ignore-ip|ignore ip address|None|[ip/subnet], Repeatable| ignore-ip 1.2.3.4/16

View File

@@ -213,6 +213,18 @@ log-level info
# ipset /www.example.com/block, set ipset with ipset name of block
# ipset /www.example.com/-, ignore this domain
# enable nftset timeout by ttl feature
# nftset-timeout [yes]
# enable nftset debug, check nftset setting result, output log when error.
# nftset-debug [no]
# specific nftset to domain
# nftset /domain/[#4:ip#table#set,#6:ipv6#table#setv6]
# nftset /www.example.com/ip#table#set, equivalent to 'nft add element ip table set { ... }'
# nftset /www.example.com/-, ignore this domain
# nftset /www.example.com/#6:-, ignore ipv6
# set domain rules
# domain-rules /domain/ [-speed-check-mode [...]]
# rules:
@@ -221,6 +233,7 @@ log-level info
# [-a] -address [address|-]: same as address option
# [-n] -nameserver [group|-]: same as nameserver option
# [-p] -ipset [ipset|-]: same as ipset option
# [-t] -nftset [nftset|-]: same as nftset option
# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option
# collection of domains

View File

@@ -16,7 +16,6 @@ showhelp()
echo " --platform [luci|luci-compat|debian|openwrt|optware|linux] build for platform. "
echo " --arch [all|armhf|arm64|x86-64|...] build for architecture, e.g. "
echo " --cross-tool [cross-tool] cross compiler, e.g. mips-openwrt-linux-"
echo " --with-nftables build with nftables support"
echo ""
echo "Advance Options:"
echo " --static static link smartdns"
@@ -109,9 +108,6 @@ main()
--cross-tool)
CROSS_TOOL="$2"
shift 2;;
--with-nftables)
MAKE_ARGS="WITH_NFTSET=1"
shift 1;;
--static)
export STATIC="yes"
shift 1;;

View File

@@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
BIN=smartdns
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.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 http_parse.o $(OBJS_LIB)
# cflags
@@ -38,11 +38,6 @@ else
override LDFLAGS += -lssl -lcrypto -lpthread -ldl
endif
ifdef WITH_NFTSET
override CFLAGS += -DWITH_NFTSET
override LDFLAGS += -lnftables
endif
.PHONY: all clean
all: $(BIN)

View File

@@ -139,6 +139,7 @@ int dns_conf_force_AAAA_SOA;
int dns_conf_force_no_cname;
int dns_conf_ipset_timeout_enable;
int dns_conf_nftset_timeout_enable;
int dns_conf_nftset_debug_enable;
char dns_conf_user[DNS_CONF_USRNAME_LEN];
@@ -984,6 +985,7 @@ static int _conf_domain_rule_nftset(char *domain, const char *nftsetname)
goto errout;
}
_dns_rule_put(&nftset_rule->head);
nftset_rule = NULL;
}
goto clear;
@@ -1834,7 +1836,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
{"speed-check-mode", required_argument, NULL, 'c'},
{"address", required_argument, NULL, 'a'},
{"ipset", required_argument, NULL, 'p'},
{"nftset", required_argument, NULL, 's'},
{"nftset", required_argument, NULL, 't'},
{"nameserver", required_argument, NULL, 'n'},
{"dualstack-ip-selection", required_argument, NULL, 'd'},
{NULL, no_argument, NULL, 0}
@@ -1920,7 +1922,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
break;
}
case 's': {
case 't': {
const char *nftsetname = optarg;
if (nftsetname == NULL) {
goto errout;
@@ -2362,6 +2364,7 @@ static struct config_item _config_item[] = {
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
CONF_CUSTOM("ipset", _config_ipset, NULL),
CONF_YESNO("nftset-timeout", &dns_conf_nftset_timeout_enable),
CONF_YESNO("nftset-debug", &dns_conf_nftset_debug_enable),
CONF_CUSTOM("nftset", _config_nftset, NULL),
CONF_CUSTOM("speed-check-mode", _config_speed_check_mode, NULL),
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),

View File

@@ -389,6 +389,7 @@ extern int dns_conf_rr_ttl_max;
extern int dns_conf_force_AAAA_SOA;
extern int dns_conf_ipset_timeout_enable;
extern int dns_conf_nftset_timeout_enable;
extern int dns_conf_nftset_debug_enable;
extern int dns_conf_local_ttl;
extern int dns_conf_force_no_cname;

View File

@@ -28,6 +28,7 @@
#include "fast_ping.h"
#include "hashtable.h"
#include "list.h"
#include "nftset.h"
#include "tlog.h"
#include "util.h"
#include <errno.h>
@@ -1397,15 +1398,19 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
ipset_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET);
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
ipset_rule_v4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV4);
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
ipset_rule_v6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV6);
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP_IGN) == 0) {
nftset_ip = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP);
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) {
nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6);
}
@@ -1429,21 +1434,19 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
if (rule != NULL) {
/* add IPV4 to ipset */
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ip_ttl * 2);
tlog(TLOG_DEBUG, "IPSET-MATCH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ip_ttl * 2);
}
#ifdef WITH_NFTSET
if (nftset_ip != NULL) {
/* add IPV4 to ipset */
nftset_add(nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr,
DNS_RR_A_LEN, request->ip_ttl * 2);
tlog(TLOG_DEBUG, "NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: %d.%d.%d.%d", request->domain,
nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr[0], addr[1],
addr[2], addr[3]);
nftset_add(nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr,
DNS_RR_A_LEN, request->ip_ttl * 2);
}
#endif
} break;
case DNS_T_AAAA: {
unsigned char addr[16];
@@ -1455,27 +1458,26 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
if (rule != NULL) {
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ip_ttl * 2);
tlog(TLOG_DEBUG,
"IPSET-MATCH: domain: %s, ipset: %s, IP: "
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
request->domain, rule->ipsetname, 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]);
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ip_ttl * 2);
}
#ifdef WITH_NFTSET
if (nftset_ip6 != NULL) {
/* add IPV6 to ipset */
nftset_add(nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname, addr,
DNS_RR_AAAA_LEN, request->ip_ttl * 2);
tlog(TLOG_DEBUG,
"NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: "
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
request->domain, nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname,
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]);
nftset_add(nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname, addr,
DNS_RR_AAAA_LEN, request->ip_ttl * 2);
}
#endif
} break;
default:
break;

36
src/include/nftset.h Normal file
View File

@@ -0,0 +1,36 @@
/*************************************************************************
*
* Copyright (C) 2018-2022Ruilin Peng (Nick) <pymumu@gmail.com>.
*
* smartdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* smartdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NFTSET_H
#define _NFTSET_H
#ifdef __cpluscplus
extern "C" {
#endif
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len, unsigned long timeout);
int nftset_del(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len);
#ifdef __cpluscplus
}
#endif
#endif // !_NFTSET_H

378
src/lib/nftset.c Normal file
View File

@@ -0,0 +1,378 @@
/*************************************************************************
*
* Copyright (C) 2018-2022 Ruilin Peng (Nick) <pymumu@gmail.com>.
*
* smartdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* smartdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include "nftset.h"
#include "../dns_conf.h"
#include "../tlog.h"
#include <errno.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <memory.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
struct nlmsgreq {
struct nlmsghdr h;
struct nfgenmsg m;
};
enum { PAYLOAD_MAX = 2048 };
static int nftset_fd;
static struct rtattr *_nftset_nlmsg_tail(struct nlmsghdr *n)
{
return (struct rtattr *)((uint8_t *)n + NLMSG_ALIGN(n->nlmsg_len));
}
static int _nftset_addattr(struct nlmsghdr *n, int maxlen, __u16 type, const void *data, __u16 alen)
{
const __u16 len = RTA_LENGTH(alen);
const ssize_t newlen = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
if (newlen > maxlen) {
errno = ENOSPC;
return -1;
}
struct rtattr *attr = _nftset_nlmsg_tail(n);
attr->rta_len = len;
attr->rta_type = type;
void *rta_data = RTA_DATA(attr);
memcpy(rta_data, data, alen);
n->nlmsg_len = newlen;
return 0;
}
static int _nftset_addattr_string(struct nlmsghdr *n, int maxlen, __u16 type, const char *s)
{
return _nftset_addattr(n, maxlen, type, s, strlen(s) + 1);
}
static int __attribute__((unused)) _nftset_addattr_uint32(struct nlmsghdr *n, int maxlen, __u16 type, const uint32_t v)
{
return _nftset_addattr(n, maxlen, type, &v, sizeof(uint32_t));
}
static int __attribute__((unused)) _nftset_addattr_uint16(struct nlmsghdr *n, int maxlen, __u16 type, const uint16_t v)
{
return _nftset_addattr(n, maxlen, type, &v, sizeof(uint16_t));
}
static int __attribute__((unused)) _nftset_addattr_uint8(struct nlmsghdr *n, int maxlen, __u16 type, const uint8_t v)
{
return _nftset_addattr(n, maxlen, type, &v, sizeof(uint8_t));
}
static struct rtattr *_nftset_addattr_nest(struct nlmsghdr *n, int maxlen, __u16 type)
{
struct rtattr *attr = _nftset_nlmsg_tail(n);
if (-1 == _nftset_addattr(n, maxlen, type, NULL, 0)) {
return NULL;
}
return attr;
}
static void _nftset_addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
{
const void *tail = _nftset_nlmsg_tail(n);
nest->rta_len = (uint8_t *)tail - (uint8_t *)nest;
}
static int _nftset_start_batch(void *buf, void **nextbuf)
{
struct nlmsgreq *req = (struct nlmsgreq *)buf;
memset(buf, 0, sizeof(struct nlmsgreq));
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
req->h.nlmsg_flags = NLM_F_REQUEST;
req->h.nlmsg_type = NFNL_MSG_BATCH_BEGIN;
req->h.nlmsg_seq = time(NULL);
req->m.res_id = NFNL_SUBSYS_NFTABLES;
if (nextbuf) {
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
}
return 0;
}
static int _nftset_end_batch(void *buf, void **nextbuf)
{
struct nlmsgreq *req = (struct nlmsgreq *)buf;
memset(buf, 0, sizeof(struct nlmsgreq));
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
req->h.nlmsg_flags = NLM_F_REQUEST;
req->h.nlmsg_type = NFNL_MSG_BATCH_END;
req->h.nlmsg_seq = time(NULL);
req->m.res_id = NFNL_SUBSYS_NFTABLES;
if (nextbuf) {
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
}
return 0;
}
static int _nftset_socket_init(void)
{
struct sockaddr_nl addr = {0};
addr.nl_family = AF_NETLINK;
addr.nl_pid = 0;
int fd = 0;
if (nftset_fd > 0) {
return 0;
}
fd = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_NETFILTER);
if (fd < 0) {
return -1;
}
if (bind(fd, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
close(fd);
return -2;
}
nftset_fd = fd;
return 0;
}
static int _nftset_socket_send(void *msg, int msg_len)
{
char recvbuff[1024];
int ret = -1;
struct pollfd pfds;
int do_recv = 0;
int last_errno = 0;
if (_nftset_socket_init() != 0) {
return -1;
}
for (;;) {
int len = send(nftset_fd, msg, msg_len, 0);
if (len == msg_len) {
break;
}
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
struct timespec waiter;
waiter.tv_sec = 0;
waiter.tv_nsec = 10000;
nanosleep(&waiter, NULL);
continue;
}
return -1;
}
if (dns_conf_nftset_debug_enable == 0) {
return 0;
}
pfds.fd = nftset_fd;
pfds.events = POLLIN;
pfds.revents = 0;
ret = poll(&pfds, 1, 100);
if (ret <= 0) {
return -1;
}
if ((pfds.revents & POLLIN) == 0) {
return -1;
}
memset(recvbuff, 0, sizeof(recvbuff));
for (;;) {
ret = recv(nftset_fd, recvbuff, 1024, 0);
if (ret < 0) {
if (errno == EAGAIN && do_recv == 1) {
break;
}
if (errno == EAGAIN && last_errno != 0) {
errno = last_errno;
}
return -1;
}
do_recv = 1;
struct nlmsghdr *nlh = (struct nlmsghdr *)recvbuff;
if (nlh->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nlh);
if (err->error != 0) {
errno = -err->error;
last_errno = errno;
return -1;
}
}
}
return 0;
}
static int _nftset_del_element(const char *table_name, const char *setname, const void *data, int data_len, void *buf,
void **nextbuf)
{
struct nlmsgreq *req = (struct nlmsgreq *)buf;
memset(buf, 0, sizeof(struct nlmsgreq));
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
req->h.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req->h.nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | NFT_MSG_DELSETELEM;
req->h.nlmsg_seq = time(NULL);
if (dns_conf_nftset_debug_enable) {
req->h.nlmsg_flags |= NLM_F_ACK;
}
req->m.nfgen_family = NFPROTO_INET;
struct nlmsghdr *n = &req->h;
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_TABLE, table_name);
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_SET, setname);
struct rtattr *nest_list = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_LIST_ELEMENTS);
struct rtattr *nest_elem = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED);
struct rtattr *nest_elem_key = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_KEY);
_nftset_addattr(n, PAYLOAD_MAX, NFTA_DATA_VALUE, data, data_len);
_nftset_addattr_nest_end(n, nest_elem_key);
_nftset_addattr_nest_end(n, nest_elem);
_nftset_addattr_nest_end(n, nest_list);
if (nextbuf) {
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
}
return 0;
}
static int _nftset_add_element(const char *table_name, const char *setname, const void *data, int data_len,
unsigned long timeout, void *buf, void **nextbuf)
{
struct nlmsgreq *req = (struct nlmsgreq *)buf;
memset(buf, 0, sizeof(struct nlmsgreq));
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
req->h.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req->h.nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | NFT_MSG_NEWSETELEM;
req->h.nlmsg_seq = time(NULL);
if (dns_conf_nftset_debug_enable) {
req->h.nlmsg_flags |= NLM_F_ACK;
}
req->m.nfgen_family = NFPROTO_INET;
struct nlmsghdr *n = &req->h;
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_TABLE, table_name);
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_SET, setname);
struct rtattr *nest_list = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_LIST_ELEMENTS);
struct rtattr *nest_elem = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED);
struct rtattr *nest_elem_key = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_KEY);
_nftset_addattr(n, PAYLOAD_MAX, NFTA_DATA_VALUE, data, data_len);
_nftset_addattr_nest_end(n, nest_elem_key);
if (timeout > 0) {
uint64_t timeout_value = htobe64(timeout * 1000);
_nftset_addattr(n, PAYLOAD_MAX, NFTA_SET_ELEM_TIMEOUT, &timeout_value, sizeof(timeout_value));
}
_nftset_addattr_nest_end(n, nest_elem);
_nftset_addattr_nest_end(n, nest_list);
if (nextbuf) {
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
}
return 0;
}
int nftset_del(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len)
{
uint8_t buf[PAYLOAD_MAX];
void *next = buf;
int buffer_len = 0;
_nftset_start_batch(next, &next);
_nftset_del_element(tablename, setname, addr, addr_len, next, &next);
_nftset_end_batch(next, &next);
buffer_len = (uint8_t *)next - buf;
int ret = _nftset_socket_send(buf, buffer_len);
if (ret != 0 && errno != ENOENT) {
tlog(TLOG_ERROR, "nftset delete failed, family:%s, table:%s, set:%s, error:%s", familyname, tablename, setname,
strerror(errno));
}
return ret;
}
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len, unsigned long timeout)
{
uint8_t buf[PAYLOAD_MAX];
void *next = buf;
int buffer_len = 0;
int ret = -1;
if (dns_conf_nftset_timeout_enable == 0) {
timeout = 0;
}
nftset_del(familyname, tablename, setname, addr, addr_len);
_nftset_start_batch(next, &next);
_nftset_add_element(tablename, setname, addr, addr_len, timeout, next, &next);
_nftset_end_batch(next, &next);
buffer_len = (uint8_t *)next - buf;
ret = _nftset_socket_send(buf, buffer_len);
if (ret != 0) {
tlog(TLOG_ERROR, "nftset add failed, family:%s, table:%s, set:%s, error:%s", familyname, tablename, setname,
strerror(errno));
}
return ret;
}

View File

@@ -31,6 +31,7 @@
#include <linux/capability.h>
#include <linux/limits.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <netinet/tcp.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
@@ -47,10 +48,6 @@
#include <unistd.h>
#include <unwind.h>
#ifdef WITH_NFTSET
#include <nftables/libnftables.h>
#endif
#define TMP_BUFF_LEN_32 32
#define NFNL_SUBSYS_IPSET 6
@@ -641,70 +638,6 @@ int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len)
return _ipset_operate(ipsetname, addr, addr_len, 0, IPSET_DEL);
}
#ifdef WITH_NFTSET
static struct nft_ctx *_nftset_init(void)
{
static struct nft_ctx *nft_ctx = NULL;
if (nft_ctx) {
return nft_ctx;
}
nft_ctx = nft_ctx_new(NFT_CTX_DEFAULT);
if (!nft_ctx) {
return NULL;
}
nft_ctx_buffer_error(nft_ctx);
return nft_ctx;
}
static int _nftset_operate(const char *familyname, const char *tablename, const char *setname,
const unsigned char addr[], int af, const char *op, const char *flags)
{
char cmd_buf[1024] = {'\0'};
struct nft_ctx *nft_ctx = _nftset_init();
if (nft_ctx == NULL) {
return -1;
}
char addr_str[INET6_ADDRSTRLEN];
if (!inet_ntop(af, addr, addr_str, INET6_ADDRSTRLEN)) {
return -1;
}
int ret = snprintf(cmd_buf, sizeof(cmd_buf), "%s element %s %s %s { %s %s }", op, familyname, tablename, setname,
addr_str, flags);
if (ret == -1) {
return -1;
}
ret = nft_run_cmd_from_buffer(nft_ctx, cmd_buf);
nft_ctx_get_error_buffer(nft_ctx);
return ret;
}
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len, unsigned long timeout)
{
char flag_timeout[32] = {'\0'};
int af = addr_len == IPV6_ADDR_LEN ? AF_INET6 : AF_INET;
if (dns_conf_nftset_timeout_enable) {
snprintf(flag_timeout, sizeof(flag_timeout), "timeout %lus", timeout);
}
return _nftset_operate(familyname, tablename, setname, addr, af, "add", flag_timeout);
}
int nftset_del(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len)
{
int af = addr_len == IPV6_ADDR_LEN ? AF_INET6 : AF_INET;
return _nftset_operate(familyname, tablename, setname, addr, af, "delete", "");
}
#endif
unsigned char *SSL_SHA256(const unsigned char *d, size_t n, unsigned char *md)
{
static unsigned char m[SHA256_DIGEST_LENGTH];
@@ -1523,4 +1456,4 @@ errout:
return -1;
}
#endif
#endif

View File

@@ -81,14 +81,6 @@ int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, u
int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len);
#ifdef WITH_NFTSET
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len, unsigned long timeout);
int nftset_del(const char *faimlyname, const char *tablename, const char *setname, const unsigned char addr[],
int addr_len);
#endif
void SSL_CRYPTO_thread_setup(void);
void SSL_CRYPTO_thread_cleanup(void);