Support ipset feature
This commit is contained in:
@@ -392,6 +392,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
|||||||
|server-tcp|Upstream TCP DNS server|None|[IP][:port] [-blacklist-ip], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tcp 8.8.8.8:53
|
|server-tcp|Upstream TCP DNS server|None|[IP][:port] [-blacklist-ip], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tcp 8.8.8.8:53
|
||||||
|server-tls|Upstream TLS DNS server|None|[IP][:port] [-blacklist-ip], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tls 8.8.8.8:853
|
|server-tls|Upstream TLS DNS server|None|[IP][:port] [-blacklist-ip], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tls 8.8.8.8:853
|
||||||
|address|Domain IP address|None|address /domain/ip| address /www.example.com/1.2.3.4
|
|address|Domain IP address|None|address /domain/ip| address /www.example.com/1.2.3.4
|
||||||
|
|ipset|Domain IPSet|None|ipset /domain/ipset|ipset /www.example.com/pass
|
||||||
|bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16
|
|bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16
|
||||||
|blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16
|
|blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16
|
||||||
|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
|
||||||
|
|||||||
@@ -392,6 +392,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
|||||||
|server-tcp|上游TCP DNS|无|[IP][:port] [-blacklist-ip],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tcp 8.8.8.8:53
|
|server-tcp|上游TCP DNS|无|[IP][:port] [-blacklist-ip],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tcp 8.8.8.8:53
|
||||||
|server-tls|上游TLS DNS|无|[IP][:port] [-blacklist-ip],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tls 8.8.8.8:853
|
|server-tls|上游TLS DNS|无|[IP][:port] [-blacklist-ip],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tls 8.8.8.8:853
|
||||||
|address|指定域名IP地址|无|address /domain/ip| address /www.example.com/1.2.3.4
|
|address|指定域名IP地址|无|address /domain/ip| address /www.example.com/1.2.3.4
|
||||||
|
|ipset|域名IPSET|None|ipset /domain/ipset|ipset /www.example.com/pass
|
||||||
|bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
|
|bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
|
||||||
|blacklist-ip|黑名单IP地址|无|[ip/subnet],可重复| blacklist-ip 1.2.3.4/16
|
|blacklist-ip|黑名单IP地址|无|[ip/subnet],可重复| blacklist-ip 1.2.3.4/16
|
||||||
|force-AAAA-SOA|强制AAAA地址返回SOA|no|[yes\|no]|force-AAAA-SOA yes
|
|force-AAAA-SOA|强制AAAA地址返回SOA|no|[yes\|no]|force-AAAA-SOA yes
|
||||||
|
|||||||
@@ -84,3 +84,7 @@ log-level info
|
|||||||
# specific address to domain
|
# specific address to domain
|
||||||
# address /domain/ip
|
# address /domain/ip
|
||||||
# address /www.example.com/1.2.3.4
|
# address /www.example.com/1.2.3.4
|
||||||
|
|
||||||
|
# specific ipset to domain
|
||||||
|
# ipset /domain/ipset
|
||||||
|
# ipset /www.example.com/block
|
||||||
132
src/dns_conf.c
132
src/dns_conf.c
@@ -11,6 +11,11 @@
|
|||||||
|
|
||||||
#define DEFAULT_DNS_CACHE_SIZE 512
|
#define DEFAULT_DNS_CACHE_SIZE 512
|
||||||
|
|
||||||
|
struct dns_ipset_table {
|
||||||
|
DECLARE_HASHTABLE(ipset, 8);
|
||||||
|
};
|
||||||
|
struct dns_ipset_table dns_ipset_table;
|
||||||
|
|
||||||
char dns_conf_server_ip[DNS_MAX_IPLEN];
|
char dns_conf_server_ip[DNS_MAX_IPLEN];
|
||||||
char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
||||||
int dns_conf_tcp_idle_time = 120;
|
int dns_conf_tcp_idle_time = 120;
|
||||||
@@ -64,10 +69,10 @@ int config_server(int argc, char *argv[], dns_server_type_t type, int default_po
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'b': {
|
case 'b': {
|
||||||
result_flag |= DNSSERVER_FLAG_BLACKLIST_IP;
|
result_flag |= DNSSERVER_FLAG_BLACKLIST_IP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +191,117 @@ errout:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void config_ipset_table_destroy(void)
|
||||||
|
{
|
||||||
|
struct dns_ipset_name *ipset_name = NULL;
|
||||||
|
struct hlist_node *tmp = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
hash_for_each_safe(dns_ipset_table.ipset, i, tmp, ipset_name, node)
|
||||||
|
{
|
||||||
|
hlist_del_init(&ipset_name->node);
|
||||||
|
free(ipset_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dns_conf_get_ipset(const char *ipsetname)
|
||||||
|
{
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct dns_ipset_name *ipset_name = NULL;
|
||||||
|
|
||||||
|
key = hash_string(ipsetname);
|
||||||
|
hash_for_each_possible(dns_ipset_table.ipset, ipset_name, node, key)
|
||||||
|
{
|
||||||
|
if (strncmp(ipset_name->ipsetname, ipsetname, DNS_MAX_IPSET_NAMELEN) == 0) {
|
||||||
|
return ipset_name->ipsetname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_name = malloc(sizeof(*ipset_name));
|
||||||
|
if (ipset_name == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = hash_string(ipsetname);
|
||||||
|
strncpy(ipset_name->ipsetname, ipsetname, DNS_MAX_IPSET_NAMELEN);
|
||||||
|
hash_add(dns_ipset_table.ipset, &ipset_name->node, key);
|
||||||
|
|
||||||
|
return ipset_name->ipsetname;
|
||||||
|
errout:
|
||||||
|
if (ipset_name) {
|
||||||
|
free(ipset_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_ipset(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct dns_ipset_rule *ipset_rule = NULL;
|
||||||
|
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||||
|
char ipsetname[DNS_MAX_CONF_CNAME_LEN];
|
||||||
|
const char *ipset = NULL;
|
||||||
|
char *begin = NULL;
|
||||||
|
char *end = NULL;
|
||||||
|
int len = 0;
|
||||||
|
char *value = argv[1];
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
len = strlen(end + 1);
|
||||||
|
if (len <= 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(ipsetname, end + 1, DNS_MAX_IPSET_NAMELEN);
|
||||||
|
ipset = dns_conf_get_ipset(ipsetname);
|
||||||
|
if (ipset == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_rule = malloc(sizeof(*ipset_rule));
|
||||||
|
if (ipset_rule == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_rule->ipsetname = ipset;
|
||||||
|
|
||||||
|
if (config_domain_rule_add(domain, DOMAIN_RULE_IPSET, ipset_rule) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
if (ipset_rule) {
|
||||||
|
free(ipset_rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_ERROR, "add ipset %s failed", value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int config_address(void *data, int argc, char *argv[])
|
int config_address(void *data, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct dns_address_IPV4 *address_ipv4 = NULL;
|
struct dns_address_IPV4 *address_ipv4 = NULL;
|
||||||
@@ -202,6 +318,10 @@ int config_address(void *data, int argc, char *argv[])
|
|||||||
socklen_t addr_len = sizeof(addr);
|
socklen_t addr_len = sizeof(addr);
|
||||||
enum domain_rule type = 0;
|
enum domain_rule type = 0;
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
begin = strstr(value, "/");
|
begin = strstr(value, "/");
|
||||||
if (begin == NULL) {
|
if (begin == NULL) {
|
||||||
goto errout;
|
goto errout;
|
||||||
@@ -385,6 +505,7 @@ struct config_item config_item[] = {
|
|||||||
CONF_CUSTOM("server-tcp", config_server_tcp, NULL),
|
CONF_CUSTOM("server-tcp", config_server_tcp, NULL),
|
||||||
CONF_CUSTOM("server-tls", config_server_tls, NULL),
|
CONF_CUSTOM("server-tls", config_server_tls, NULL),
|
||||||
CONF_CUSTOM("address", config_address, NULL),
|
CONF_CUSTOM("address", config_address, NULL),
|
||||||
|
CONF_CUSTOM("ipset", config_ipset, NULL),
|
||||||
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
||||||
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
|
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
|
||||||
CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
|
CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
|
||||||
@@ -426,6 +547,8 @@ int _dns_server_load_conf_init(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash_init(dns_ipset_table.ipset);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,6 +556,7 @@ void dns_server_load_exit(void)
|
|||||||
{
|
{
|
||||||
config_domain_destroy();
|
config_domain_destroy();
|
||||||
Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
|
Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
|
||||||
|
config_ipset_table_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
int dns_server_load_conf(const char *file)
|
int dns_server_load_conf(const char *file)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "radix.h"
|
#include "radix.h"
|
||||||
|
|
||||||
#define DNS_MAX_SERVERS 32
|
#define DNS_MAX_SERVERS 32
|
||||||
|
#define DNS_MAX_IPSET_NAMELEN 32
|
||||||
#define DNS_MAX_IPLEN 64
|
#define DNS_MAX_IPLEN 64
|
||||||
#define DNS_MAX_PATH 1024
|
#define DNS_MAX_PATH 1024
|
||||||
#define DEFAULT_DNS_PORT 53
|
#define DEFAULT_DNS_PORT 53
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
enum domain_rule {
|
enum domain_rule {
|
||||||
DOMAIN_RULE_ADDRESS_IPV4 = 1,
|
DOMAIN_RULE_ADDRESS_IPV4 = 1,
|
||||||
DOMAIN_RULE_ADDRESS_IPV6 = 2,
|
DOMAIN_RULE_ADDRESS_IPV6 = 2,
|
||||||
|
DOMAIN_RULE_IPSET = 3,
|
||||||
DOMAIN_RULE_MAX,
|
DOMAIN_RULE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,6 +36,15 @@ struct dns_address_IPV6 {
|
|||||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dns_ipset_name {
|
||||||
|
struct hlist_node node;
|
||||||
|
char ipsetname[DNS_MAX_IPSET_NAMELEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_ipset_rule {
|
||||||
|
const char *ipsetname;
|
||||||
|
};
|
||||||
|
|
||||||
struct dns_domain_rule {
|
struct dns_domain_rule {
|
||||||
void *rules[DOMAIN_RULE_MAX];
|
void *rules[DOMAIN_RULE_MAX];
|
||||||
};
|
};
|
||||||
@@ -66,10 +77,6 @@ struct dns_ip_address_rule {
|
|||||||
unsigned int bogus : 1;
|
unsigned int bogus : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dns_bogus_nxdomain {
|
|
||||||
DECLARE_HASHTABLE(ip_hash, 12);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern char dns_conf_server_ip[DNS_MAX_IPLEN];
|
extern char dns_conf_server_ip[DNS_MAX_IPLEN];
|
||||||
extern char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
extern char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
||||||
extern int dns_conf_tcp_idle_time;
|
extern int dns_conf_tcp_idle_time;
|
||||||
|
|||||||
@@ -419,6 +419,36 @@ static int _dns_reply(struct dns_request *request)
|
|||||||
return _dns_reply_inpacket(request, inpacket, encode_len);
|
return _dns_reply_inpacket(request, inpacket, encode_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_setup_ipset(struct dns_request *request)
|
||||||
|
{
|
||||||
|
struct dns_ipset_rule *ipset_rule = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (request->domain_rule == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_rule = request->domain_rule->rules[DOMAIN_RULE_IPSET];
|
||||||
|
if (ipset_rule == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->has_ipv4 && request->qtype == DNS_T_A) {
|
||||||
|
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->has_ipv6 && request->qtype == DNS_T_AAAA) {
|
||||||
|
if (request->has_ipv4) {
|
||||||
|
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN);
|
||||||
|
}
|
||||||
|
ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, result: %d", request->domain, ipset_rule->ipsetname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int _dns_server_request_complete(struct dns_request *request)
|
int _dns_server_request_complete(struct dns_request *request)
|
||||||
{
|
{
|
||||||
char *cname = NULL;
|
char *cname = NULL;
|
||||||
@@ -476,6 +506,7 @@ int _dns_server_request_complete(struct dns_request *request)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_dns_setup_ipset(request);
|
||||||
_dns_reply(request);
|
_dns_reply(request);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
163
src/util.c
163
src/util.c
@@ -2,11 +2,57 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define NFNL_SUBSYS_IPSET 6
|
||||||
|
|
||||||
|
#define IPSET_ATTR_DATA 7
|
||||||
|
#define IPSET_ATTR_IP 1
|
||||||
|
#define IPSET_ATTR_IPADDR_IPV4 1
|
||||||
|
#define IPSET_ATTR_IPADDR_IPV6 2
|
||||||
|
#define IPSET_ATTR_PROTOCOL 1
|
||||||
|
#define IPSET_ATTR_SETNAME 2
|
||||||
|
#define IPSET_ADD 9
|
||||||
|
#define IPSET_DEL 10
|
||||||
|
#define IPSET_MAXNAMELEN 32
|
||||||
|
#define IPSET_PROTOCOL 6
|
||||||
|
|
||||||
|
#define IPV6_ADDR_LEN 16
|
||||||
|
#define IPV4_ADDR_LEN 4
|
||||||
|
|
||||||
|
#ifndef NFNETLINK_V0
|
||||||
|
#define NFNETLINK_V0 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NLA_F_NESTED
|
||||||
|
#define NLA_F_NESTED (1 << 15)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NLA_F_NET_BYTEORDER
|
||||||
|
#define NLA_F_NET_BYTEORDER (1 << 14)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NETLINK_ALIGN(len) (((len) + 3) & ~(3))
|
||||||
|
|
||||||
|
#define BUFF_SZ 256
|
||||||
|
|
||||||
|
struct ipset_netlink_attr {
|
||||||
|
unsigned short len;
|
||||||
|
unsigned short type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipset_netlink_msg {
|
||||||
|
unsigned char family;
|
||||||
|
unsigned char version;
|
||||||
|
__be16 res_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ipset_fd;
|
||||||
|
|
||||||
unsigned long get_tick_count(void)
|
unsigned long get_tick_count(void)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
@@ -159,7 +205,7 @@ char *reverse_string(char *output, char *input, int len)
|
|||||||
*output = 0;
|
*output = 0;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
len--;
|
len--;
|
||||||
while (len >= 0) {
|
while (len >= 0) {
|
||||||
*output = *(input + len);
|
*output = *(input + len);
|
||||||
@@ -171,3 +217,118 @@ char *reverse_string(char *output, char *input, int len)
|
|||||||
|
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
uint16_t payload_len = NETLINK_ALIGN(sizeof(struct ipset_netlink_attr)) + len;
|
||||||
|
attr->type = type;
|
||||||
|
attr->len = payload_len;
|
||||||
|
memcpy((void *)attr + NETLINK_ALIGN(sizeof(struct ipset_netlink_attr)), data, len);
|
||||||
|
netlink_head->nlmsg_len += NETLINK_ALIGN(payload_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _ipset_socket_init(void)
|
||||||
|
{
|
||||||
|
if (ipset_fd > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
|
||||||
|
|
||||||
|
if (ipset_fd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, int operate)
|
||||||
|
{
|
||||||
|
struct nlmsghdr *netlink_head;
|
||||||
|
struct ipset_netlink_msg *netlink_msg;
|
||||||
|
struct ipset_netlink_attr *nested[2];
|
||||||
|
char buffer[BUFF_SZ];
|
||||||
|
uint8_t proto;
|
||||||
|
ssize_t rc;
|
||||||
|
int af = 0;
|
||||||
|
static const struct sockaddr_nl snl = {.nl_family = AF_NETLINK};
|
||||||
|
|
||||||
|
if (addr_len != IPV4_ADDR_LEN && addr_len != IPV6_ADDR_LEN) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_len == IPV4_ADDR_LEN) {
|
||||||
|
af = AF_INET;
|
||||||
|
} else if (addr_len == IPV6_ADDR_LEN) {
|
||||||
|
af = AF_INET6;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_ipset_socket_init() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(ipsetname) >= IPSET_MAXNAMELEN) {
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buffer, 0, BUFF_SZ);
|
||||||
|
|
||||||
|
netlink_head = (struct nlmsghdr *)buffer;
|
||||||
|
netlink_head->nlmsg_len = NETLINK_ALIGN(sizeof(struct nlmsghdr));
|
||||||
|
netlink_head->nlmsg_type = operate | (NFNL_SUBSYS_IPSET << 8);
|
||||||
|
netlink_head->nlmsg_flags = NLM_F_REQUEST;
|
||||||
|
|
||||||
|
netlink_msg = (struct ipset_netlink_msg *)(buffer + netlink_head->nlmsg_len);
|
||||||
|
netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_msg));
|
||||||
|
netlink_msg->family = af;
|
||||||
|
netlink_msg->version = NFNETLINK_V0;
|
||||||
|
netlink_msg->res_id = htons(0);
|
||||||
|
|
||||||
|
proto = IPSET_PROTOCOL;
|
||||||
|
_ipset_add_attr(netlink_head, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
|
||||||
|
_ipset_add_attr(netlink_head, IPSET_ATTR_SETNAME, strlen(ipsetname) + 1, ipsetname);
|
||||||
|
|
||||||
|
nested[0] = (struct ipset_netlink_attr *)(buffer + NETLINK_ALIGN(netlink_head->nlmsg_len));
|
||||||
|
netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_attr));
|
||||||
|
nested[0]->type = NLA_F_NESTED | IPSET_ATTR_DATA;
|
||||||
|
nested[1] = (struct ipset_netlink_attr *)(buffer + NETLINK_ALIGN(netlink_head->nlmsg_len));
|
||||||
|
netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_attr));
|
||||||
|
nested[1]->type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||||
|
_ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr);
|
||||||
|
|
||||||
|
nested[1]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[1];
|
||||||
|
nested[0]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[0];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rc = sendto(ipset_fd, buffer, netlink_head->nlmsg_len, 0, (struct sockaddr *)&snl, sizeof(snl));
|
||||||
|
if (rc >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
|
||||||
|
struct timespec waiter;
|
||||||
|
waiter.tv_sec = 0;
|
||||||
|
waiter.tv_nsec = 10000;
|
||||||
|
nanosleep(&waiter, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len)
|
||||||
|
{
|
||||||
|
return _ipset_operate(ipsetname, addr, addr_len, IPSET_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len)
|
||||||
|
{
|
||||||
|
return _ipset_operate(ipsetname, addr, addr_len, IPSET_DEL);
|
||||||
|
}
|
||||||
@@ -22,4 +22,8 @@ char *reverse_string(char *output, 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);
|
||||||
|
|
||||||
|
int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user