edit config parser to support ipset

This commit is contained in:
Kevin Chu 2019-05-03 17:45:34 +08:00
parent 1a48bdebb5
commit 56af87e2f3
6 changed files with 394 additions and 285 deletions

View file

@ -653,6 +653,9 @@ server:
# local-zone: "8.b.d.0.1.0.0.2.ip6.arpa." nodefault
# And for 64.100.in-addr.arpa. to 127.100.in-addr.arpa.
# Add example.com into ipset
# local-zone: "example.com" ipset
# If unbound is running service for the local host then it is useful
# to perform lan-wide lookups to the upstream, and unblock the
# long list of local-zones above. If this unbound is a dns server
@ -991,3 +994,14 @@ remote-control:
# redis-server-port: 6379
# # timeout (in ms) for communication with the redis server
# redis-timeout: 100
# IPSet
# Add specify domain into set via ipset.
# Note: To enable ipset needs run unbound as root user.
# ipset:
# # set name for ip v4 addresses
# name-v4: "list-v4"
# # set name for ip v6 addresses
# name-v6: "list-v6"
#

View file

@ -2,10 +2,12 @@
#include "ipset/ipset.h"
#include "util/regional.h"
#include "util/config_file.h"
#include "services/cache/dns.h"
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
#include "sldns/parseutil.h"
#include <libmnl/libmnl.h>
#include <linux/netfilter/nfnetlink.h>
@ -21,8 +23,7 @@
* @return: 0 for use by caller, to make notation easy, like:
* return error_response(..).
*/
static int error_response(struct module_qstate* qstate, int id, int rcode)
{
static int error_response(struct module_qstate* qstate, int id, int rcode) {
verbose(VERB_QUERY, "return error response %s",
sldns_lookup_by_id(sldns_rcodes, rcode)?
sldns_lookup_by_id(sldns_rcodes, rcode)->name:"??");
@ -36,7 +37,7 @@ static int add_to_ipset(struct mnl_socket *mnl, const char *setname, const void
struct nlmsghdr *nlh;
struct nfgenmsg *nfg;
struct nlattr *nested[2];
char buffer[BUFF_LEN];
static char buffer[BUFF_LEN];
if (strlen(setname) >= IPSET_MAXNAMELEN) {
errno = ENAMETOOLONG;
@ -49,7 +50,7 @@ static int add_to_ipset(struct mnl_socket *mnl, const char *setname, const void
nlh = mnl_nlmsg_put_header(buffer);
nlh->nlmsg_type = IPSET_CMD_ADD | (NFNL_SUBSYS_IPSET << 8);
nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL;
nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL;
nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
nfg->nfgen_family = af;
@ -71,29 +72,40 @@ static int add_to_ipset(struct mnl_socket *mnl, const char *setname, const void
return 0;
}
int ipset_update(struct dns_msg* return_msg, struct ipset_env *ie) {
int i, j;
static int ipset_update(struct module_env *env, struct dns_msg *return_msg, struct ipset_env *ie) {
int ret;
int af;
uint16_t rrtype;
size_t rr_len, rd_len;
struct ub_packed_rrset_key *rrset;
struct packed_rrset_data* d;
uint8_t *rr_data;
struct mnl_socket *mnl;
int i, j;
const char *setname;
struct mnl_socket *mnl;
struct ub_packed_rrset_key *rrset;
struct packed_rrset_data *d;
int af;
static char dname[BUFF_LEN];
const char *s;
int dlen, plen;
struct config_strlist *p;
uint16_t rrtype;
size_t rr_len, rd_len;
uint8_t *rr_data;
mnl = (struct mnl_socket *)ie->mnl;
if (mnl == NULL) {
return -1;
}
for (i = 0; i < return_msg->rep->rrset_count; ++i) {
for (i = 0; i < return_msg->rep->rrset_count; ++i) {
setname = NULL;
rrset = return_msg->rep->rrsets[i];
rrset = return_msg->rep->rrsets[i];
if (rrset->rk.type == htons(LDNS_RR_TYPE_A)) {
af = AF_INET;
@ -107,20 +119,46 @@ int ipset_update(struct dns_msg* return_msg, struct ipset_env *ie) {
}
}
if (setname != NULL) {
d = (struct packed_rrset_data*)rrset->entry.data;
for (j = 0; j < d->count + d->rrsig_count; j++) {
rr_len = d->rr_len[j];
rr_data = d->rr_data[j];
if (setname != NULL) {
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN);
if (dlen == 0) {
log_err("bad domain name");
return -1;
}
if (dname[dlen - 1] == '.') {
dlen--;
dname[dlen] = 0;
}
rd_len = sldns_read_uint16(rr_data);
if (rr_len - 2 >= rd_len) {
ret = add_to_ipset(mnl, setname, rr_data + 2, af);
if (ret < 0) {
return ret;
}
}
}
verbose(VERB_QUERY, "ipset domain name %d %s", dlen, dname);
for (p = env->cfg->local_zones_ipset; p; p = p->next) {
plen = strlen(p->str);
verbose(VERB_QUERY, "ipset local_zones_ipset name %d %s", plen, p->str);
if (dlen >= plen) {
s = dname + (dlen - plen);
verbose(VERB_QUERY, "ipset start name %s", s);
if (strncasecmp(p->str, s, plen) == 0) {
d = (struct packed_rrset_data*)rrset->entry.data;
for (j = 0; j < d->count + d->rrsig_count; j++) {
rr_len = d->rr_len[j];
rr_data = d->rr_data[j];
rd_len = sldns_read_uint16(rr_data);
if (rr_len - 2 >= rd_len) {
ret = add_to_ipset(mnl, setname, rr_data + 2, af);
if (ret < 0) {
return ret;
}
}
}
}
}
}
}
}
@ -222,7 +260,7 @@ void ipset_operate(struct module_qstate *qstate, enum module_ev event, int id,
}
if(iq && (event == module_event_moddone)) {
ipset_update(qstate->return_msg, ie);
ipset_update(qstate->env, qstate->return_msg, ie);
qstate->ext_state[id] = module_finished;
return;
}
@ -287,3 +325,4 @@ struct module_func_block * ipset_get_funcblock(void) {
return &ipset_block;
}

View file

@ -255,6 +255,9 @@ config_create(void)
cfg->neg_cache_size = 1 * 1024 * 1024;
cfg->local_zones = NULL;
cfg->local_zones_nodefault = NULL;
#ifdef USE_IPSET
cfg->local_zones_ipset = NULL;
#endif
cfg->local_zones_disable_default = 0;
cfg->local_data = NULL;
cfg->local_zone_overrides = NULL;
@ -1318,6 +1321,9 @@ config_delview(struct config_view* p)
free(p->name);
config_deldblstrlist(p->local_zones);
config_delstrlist(p->local_zones_nodefault);
#ifdef USE_IPSET
config_delstrlist(p->local_zones_ipset);
#endif
config_delstrlist(p->local_data);
free(p);
}
@ -1408,6 +1414,9 @@ config_delete(struct config_file* cfg)
free(cfg->val_nsec3_key_iterations);
config_deldblstrlist(cfg->local_zones);
config_delstrlist(cfg->local_zones_nodefault);
#ifdef USE_IPSET
config_delstrlist(cfg->local_zones_ipset);
#endif
config_delstrlist(cfg->local_data);
config_deltrplstrlist(cfg->local_zone_overrides);
config_del_strarray(cfg->tagname, cfg->num_tags);
@ -2119,6 +2128,11 @@ cfg_parse_local_zone(struct config_file* cfg, const char* val)
if(strcmp(type, "nodefault")==0) {
return cfg_strlist_insert(&cfg->local_zones_nodefault,
strdup(name));
#ifdef USE_IPSET
} else if(strcmp(type, "ipset")==0) {
return cfg_strlist_insert(&cfg->local_zones_ipset,
strdup(name));
#endif
} else {
return cfg_str2list_insert(&cfg->local_zones, strdup(buf),
strdup(type));
@ -2393,3 +2407,4 @@ int options_remote_is_address(struct config_file* cfg)
if(cfg->control_ifs.first->str[0] == 0) return 1;
return (cfg->control_ifs.first->str[0] != '/');
}

View file

@ -384,6 +384,10 @@ struct config_file {
struct config_str2list* local_zones;
/** local zones nodefault list */
struct config_strlist* local_zones_nodefault;
#ifdef USE_IPSET
/** local zones ipset list */
struct config_strlist* local_zones_ipset;
#endif
/** do not add any default local zone */
int local_zones_disable_default;
/** local data RRs configured */
@ -653,6 +657,10 @@ struct config_view {
struct config_strlist* local_data;
/** local zones nodefault list */
struct config_strlist* local_zones_nodefault;
#ifdef USE_IPSET
/** local zones ipset list */
struct config_strlist* local_zones_ipset;
#endif
/** Fallback to global local_zones when there is no match in the view
* view specific tree. 1 for yes, 0 for no */
int isfirst;
@ -1187,3 +1195,4 @@ void w_config_adjust_directory(struct config_file* cfg);
extern int fake_dsa, fake_sha1;
#endif /* UTIL_CONFIG_FILE_H */

File diff suppressed because it is too large Load diff

View file

@ -175,7 +175,7 @@ toplevelvar: serverstart contents_server | stubstart contents_stub |
forwardstart contents_forward | pythonstart contents_py |
rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
dnscstart contents_dnsc | cachedbstart contents_cachedb |
ipsetstart contents_ipset | authstart contents_auth
ipsetstart contents_ipset | authstart contents_auth
;
/* server: declaration */
@ -1785,13 +1785,14 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
&& strcmp($3, "always_nxdomain")!=0
&& strcmp($3, "noview")!=0
&& strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0
&& strcmp($3, "inform_redirect") != 0) {
&& strcmp($3, "inform_redirect") != 0
&& strcmp($3, "ipset") != 0) {
yyerror("local-zone type: expected static, deny, "
"refuse, redirect, transparent, "
"typetransparent, inform, inform_deny, "
"inform_redirect, always_transparent, "
"always_refuse, always_nxdomain, noview "
"or nodefault");
", nodefault or ipset");
free($2);
free($3);
} else if(strcmp($3, "nodefault")==0) {
@ -1799,6 +1800,13 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
local_zones_nodefault, $2))
fatal_exit("out of memory adding local-zone");
free($3);
#ifdef USE_IPSET
} else if(strcmp($3, "ipset")==0) {
if(!cfg_strlist_insert(&cfg_parser->cfg->
local_zones_ipset, $2))
fatal_exit("out of memory adding local-zone");
free($3);
#endif
} else {
if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones,
$2, $3))
@ -2456,6 +2464,13 @@ view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
local_zones_nodefault, $2))
fatal_exit("out of memory adding local-zone");
free($3);
#ifdef USE_IPSET
} else if(strcmp($3, "ipset")==0) {
if(!cfg_strlist_insert(&cfg_parser->cfg->views->
local_zones_ipset, $2))
fatal_exit("out of memory adding local-zone");
free($3);
#endif
} else {
if(!cfg_str2list_insert(
&cfg_parser->cfg->views->local_zones,
@ -3019,3 +3034,4 @@ validate_respip_action(const char* action)
}
}