Home | History | Annotate | Line # | Download | only in ipset
      1      1.1  christos /**
      2      1.1  christos  * \file
      3      1.1  christos  * This file implements the ipset module.  It can handle packets by putting
      4      1.1  christos  * the A and AAAA addresses that are configured in unbound.conf as type
      5      1.1  christos  * ipset (local-zone statements) into a firewall rule IPSet.  For firewall
      6      1.1  christos  * blacklist and whitelist usage.
      7      1.1  christos  */
      8      1.1  christos #include "config.h"
      9      1.1  christos #include "ipset/ipset.h"
     10      1.1  christos #include "util/regional.h"
     11      1.1  christos #include "util/net_help.h"
     12      1.1  christos #include "util/config_file.h"
     13      1.1  christos 
     14      1.1  christos #include "services/cache/dns.h"
     15      1.1  christos 
     16      1.1  christos #include "sldns/sbuffer.h"
     17      1.1  christos #include "sldns/wire2str.h"
     18      1.1  christos #include "sldns/parseutil.h"
     19      1.1  christos 
     20  1.1.1.4  christos #ifdef HAVE_NET_PFVAR_H
     21  1.1.1.4  christos #include <fcntl.h>
     22  1.1.1.4  christos #include <sys/ioctl.h>
     23  1.1.1.4  christos #include <netinet/in.h>
     24  1.1.1.4  christos #include <net/if.h>
     25  1.1.1.4  christos #include <net/pfvar.h>
     26  1.1.1.4  christos typedef intptr_t filter_dev;
     27  1.1.1.4  christos #else
     28      1.1  christos #include <libmnl/libmnl.h>
     29      1.1  christos #include <linux/netfilter/nfnetlink.h>
     30      1.1  christos #include <linux/netfilter/ipset/ip_set.h>
     31  1.1.1.4  christos typedef struct mnl_socket * filter_dev;
     32  1.1.1.4  christos #endif
     33      1.1  christos 
     34      1.1  christos #define BUFF_LEN 256
     35      1.1  christos 
     36      1.1  christos /**
     37      1.1  christos  * Return an error
     38      1.1  christos  * @param qstate: our query state
     39      1.1  christos  * @param id: module id
     40      1.1  christos  * @param rcode: error code (DNS errcode).
     41      1.1  christos  * @return: 0 for use by caller, to make notation easy, like:
     42      1.1  christos  * 	return error_response(..).
     43      1.1  christos  */
     44      1.1  christos static int error_response(struct module_qstate* qstate, int id, int rcode) {
     45      1.1  christos 	verbose(VERB_QUERY, "return error response %s",
     46      1.1  christos 		sldns_lookup_by_id(sldns_rcodes, rcode)?
     47      1.1  christos 		sldns_lookup_by_id(sldns_rcodes, rcode)->name:"??");
     48      1.1  christos 	qstate->return_rcode = rcode;
     49      1.1  christos 	qstate->return_msg = NULL;
     50      1.1  christos 	qstate->ext_state[id] = module_finished;
     51      1.1  christos 	return 0;
     52      1.1  christos }
     53      1.1  christos 
     54  1.1.1.4  christos #ifdef HAVE_NET_PFVAR_H
     55  1.1.1.4  christos static void * open_filter() {
     56  1.1.1.4  christos 	filter_dev dev;
     57  1.1.1.4  christos 
     58  1.1.1.4  christos 	dev = open("/dev/pf", O_RDWR);
     59  1.1.1.4  christos 	if (dev == -1) {
     60  1.1.1.4  christos 		log_err("open(\"/dev/pf\") failed: %s", strerror(errno));
     61  1.1.1.4  christos 		return NULL;
     62  1.1.1.4  christos 	}
     63  1.1.1.4  christos 	else
     64  1.1.1.4  christos 		return (void *)dev;
     65  1.1.1.4  christos }
     66  1.1.1.4  christos #else
     67  1.1.1.4  christos static void * open_filter() {
     68  1.1.1.4  christos 	filter_dev dev;
     69      1.1  christos 
     70  1.1.1.4  christos 	dev = mnl_socket_open(NETLINK_NETFILTER);
     71  1.1.1.4  christos 	if (!dev) {
     72      1.1  christos 		log_err("ipset: could not open netfilter.");
     73      1.1  christos 		return NULL;
     74      1.1  christos 	}
     75      1.1  christos 
     76  1.1.1.4  christos 	if (mnl_socket_bind(dev, 0, MNL_SOCKET_AUTOPID) < 0) {
     77  1.1.1.4  christos 		mnl_socket_close(dev);
     78      1.1  christos 		log_err("ipset: could not bind netfilter.");
     79      1.1  christos 		return NULL;
     80      1.1  christos 	}
     81  1.1.1.4  christos 	return (void *)dev;
     82      1.1  christos }
     83  1.1.1.4  christos #endif
     84  1.1.1.4  christos 
     85  1.1.1.4  christos #ifdef HAVE_NET_PFVAR_H
     86  1.1.1.4  christos static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr, int af) {
     87  1.1.1.4  christos 	struct pfioc_table io;
     88  1.1.1.4  christos 	struct pfr_addr addr;
     89  1.1.1.4  christos 	const char *p;
     90  1.1.1.4  christos 	int i;
     91  1.1.1.4  christos 
     92  1.1.1.4  christos 	bzero(&io, sizeof(io));
     93  1.1.1.4  christos 	bzero(&addr, sizeof(addr));
     94  1.1.1.4  christos 
     95  1.1.1.4  christos 	p = strrchr(setname, '/');
     96  1.1.1.4  christos 	if (p) {
     97  1.1.1.4  christos 		i = p - setname;
     98  1.1.1.4  christos 		if (i >= PATH_MAX) {
     99  1.1.1.4  christos 			errno = ENAMETOOLONG;
    100  1.1.1.4  christos 			return -1;
    101  1.1.1.4  christos 		}
    102  1.1.1.4  christos 		memcpy(io.pfrio_table.pfrt_anchor, setname, i);
    103  1.1.1.4  christos 		if (i < PATH_MAX)
    104  1.1.1.4  christos 			io.pfrio_table.pfrt_anchor[i] = '\0';
    105  1.1.1.4  christos 		p++;
    106  1.1.1.4  christos 	}
    107  1.1.1.4  christos 	else
    108  1.1.1.4  christos 		p = setname;
    109      1.1  christos 
    110  1.1.1.4  christos 	if (strlen(p) >= PF_TABLE_NAME_SIZE) {
    111  1.1.1.4  christos 		errno = ENAMETOOLONG;
    112  1.1.1.4  christos 		return -1;
    113  1.1.1.4  christos 	}
    114  1.1.1.4  christos 	strlcpy(io.pfrio_table.pfrt_name, p, PF_TABLE_NAME_SIZE);
    115  1.1.1.4  christos 
    116  1.1.1.4  christos 	io.pfrio_buffer = &addr;
    117  1.1.1.4  christos 	io.pfrio_size = 1;
    118  1.1.1.4  christos 	io.pfrio_esize = sizeof(addr);
    119  1.1.1.4  christos 
    120  1.1.1.4  christos 	switch (af) {
    121  1.1.1.4  christos 		case AF_INET:
    122  1.1.1.4  christos 			addr.pfra_ip4addr = *(struct in_addr *)ipaddr;
    123  1.1.1.4  christos 			addr.pfra_net = 32;
    124  1.1.1.4  christos 			break;
    125  1.1.1.4  christos 		case AF_INET6:
    126  1.1.1.4  christos 			addr.pfra_ip6addr = *(struct in6_addr *)ipaddr;
    127  1.1.1.4  christos 			addr.pfra_net = 128;
    128  1.1.1.4  christos 			break;
    129  1.1.1.4  christos 		default:
    130  1.1.1.4  christos 		errno = EAFNOSUPPORT;
    131  1.1.1.4  christos 		return -1;
    132  1.1.1.4  christos 	}
    133  1.1.1.4  christos 	addr.pfra_af = af;
    134  1.1.1.4  christos 
    135  1.1.1.4  christos 	if (ioctl(dev, DIOCRADDADDRS, &io) == -1) {
    136  1.1.1.4  christos 		log_err("ioctl failed: %s", strerror(errno));
    137  1.1.1.4  christos 		return -1;
    138  1.1.1.4  christos 	}
    139  1.1.1.4  christos 	return 0;
    140  1.1.1.4  christos }
    141  1.1.1.4  christos #else
    142  1.1.1.4  christos static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr, int af) {
    143      1.1  christos 	struct nlmsghdr *nlh;
    144      1.1  christos 	struct nfgenmsg *nfg;
    145      1.1  christos 	struct nlattr *nested[2];
    146      1.1  christos 	static char buffer[BUFF_LEN];
    147      1.1  christos 
    148      1.1  christos 	if (strlen(setname) >= IPSET_MAXNAMELEN) {
    149      1.1  christos 		errno = ENAMETOOLONG;
    150      1.1  christos 		return -1;
    151      1.1  christos 	}
    152      1.1  christos 	if (af != AF_INET && af != AF_INET6) {
    153      1.1  christos 		errno = EAFNOSUPPORT;
    154      1.1  christos 		return -1;
    155      1.1  christos 	}
    156      1.1  christos 
    157      1.1  christos 	nlh = mnl_nlmsg_put_header(buffer);
    158      1.1  christos 	nlh->nlmsg_type = IPSET_CMD_ADD | (NFNL_SUBSYS_IPSET << 8);
    159      1.1  christos 	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL;
    160      1.1  christos 
    161      1.1  christos 	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
    162      1.1  christos 	nfg->nfgen_family = af;
    163      1.1  christos 	nfg->version = NFNETLINK_V0;
    164      1.1  christos 	nfg->res_id = htons(0);
    165      1.1  christos 
    166      1.1  christos 	mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
    167      1.1  christos 	mnl_attr_put(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
    168      1.1  christos 	nested[0] = mnl_attr_nest_start(nlh, IPSET_ATTR_DATA);
    169      1.1  christos 	nested[1] = mnl_attr_nest_start(nlh, IPSET_ATTR_IP);
    170      1.1  christos 	mnl_attr_put(nlh, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6)
    171      1.1  christos 			| NLA_F_NET_BYTEORDER, (af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)), ipaddr);
    172      1.1  christos 	mnl_attr_nest_end(nlh, nested[1]);
    173      1.1  christos 	mnl_attr_nest_end(nlh, nested[0]);
    174      1.1  christos 
    175  1.1.1.4  christos 	if (mnl_socket_sendto(dev, nlh, nlh->nlmsg_len) < 0) {
    176      1.1  christos 		return -1;
    177      1.1  christos 	}
    178      1.1  christos 	return 0;
    179      1.1  christos }
    180  1.1.1.4  christos #endif
    181      1.1  christos 
    182      1.1  christos static void
    183  1.1.1.4  christos ipset_add_rrset_data(struct ipset_env *ie,
    184      1.1  christos 	struct packed_rrset_data *d, const char* setname, int af,
    185      1.1  christos 	const char* dname)
    186      1.1  christos {
    187      1.1  christos 	int ret;
    188      1.1  christos 	size_t j, rr_len, rd_len;
    189      1.1  christos 	uint8_t *rr_data;
    190      1.1  christos 
    191      1.1  christos 	/* to d->count, not d->rrsig_count, because we do not want to add the RRSIGs, only the addresses */
    192      1.1  christos 	for (j = 0; j < d->count; j++) {
    193      1.1  christos 		rr_len = d->rr_len[j];
    194      1.1  christos 		rr_data = d->rr_data[j];
    195      1.1  christos 
    196      1.1  christos 		rd_len = sldns_read_uint16(rr_data);
    197      1.1  christos 		if(af == AF_INET && rd_len != INET_SIZE)
    198      1.1  christos 			continue;
    199      1.1  christos 		if(af == AF_INET6 && rd_len != INET6_SIZE)
    200      1.1  christos 			continue;
    201      1.1  christos 		if (rr_len - 2 >= rd_len) {
    202      1.1  christos 			if(verbosity >= VERB_QUERY) {
    203      1.1  christos 				char ip[128];
    204      1.1  christos 				if(inet_ntop(af, rr_data+2, ip, (socklen_t)sizeof(ip)) == 0)
    205      1.1  christos 					snprintf(ip, sizeof(ip), "(inet_ntop_error)");
    206      1.1  christos 				verbose(VERB_QUERY, "ipset: add %s to %s for %s", ip, setname, dname);
    207      1.1  christos 			}
    208  1.1.1.4  christos 			ret = add_to_ipset((filter_dev)ie->dev, setname, rr_data + 2, af);
    209      1.1  christos 			if (ret < 0) {
    210      1.1  christos 				log_err("ipset: could not add %s into %s", dname, setname);
    211      1.1  christos 
    212  1.1.1.4  christos #if HAVE_NET_PFVAR_H
    213  1.1.1.4  christos 				/* don't close as we might not be able to open again due to dropped privs */
    214  1.1.1.4  christos #else
    215  1.1.1.4  christos 				mnl_socket_close((filter_dev)ie->dev);
    216  1.1.1.4  christos 				ie->dev = NULL;
    217  1.1.1.4  christos #endif
    218      1.1  christos 				break;
    219      1.1  christos 			}
    220      1.1  christos 		}
    221      1.1  christos 	}
    222      1.1  christos }
    223      1.1  christos 
    224      1.1  christos static int
    225      1.1  christos ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
    226  1.1.1.4  christos 	struct ub_packed_rrset_key *rrset, const char *qname, int qlen,
    227  1.1.1.4  christos 	const char *setname, int af)
    228      1.1  christos {
    229      1.1  christos 	static char dname[BUFF_LEN];
    230  1.1.1.2  christos 	const char *ds, *qs;
    231      1.1  christos 	int dlen, plen;
    232      1.1  christos 
    233      1.1  christos 	struct config_strlist *p;
    234      1.1  christos 	struct packed_rrset_data *d;
    235      1.1  christos 
    236      1.1  christos 	dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN);
    237      1.1  christos 	if (dlen == 0) {
    238      1.1  christos 		log_err("bad domain name");
    239      1.1  christos 		return -1;
    240      1.1  christos 	}
    241  1.1.1.4  christos 	if (dname[dlen - 1] == '.') {
    242  1.1.1.4  christos 		dlen--;
    243  1.1.1.4  christos 	}
    244  1.1.1.4  christos 	if (qname[qlen - 1] == '.') {
    245  1.1.1.4  christos 		qlen--;
    246  1.1.1.4  christos 	}
    247      1.1  christos 
    248      1.1  christos 	for (p = env->cfg->local_zones_ipset; p; p = p->next) {
    249  1.1.1.2  christos 		ds = NULL;
    250  1.1.1.2  christos 		qs = NULL;
    251      1.1  christos 		plen = strlen(p->str);
    252  1.1.1.4  christos 		if (p->str[plen - 1] == '.') {
    253  1.1.1.4  christos 			plen--;
    254  1.1.1.4  christos 		}
    255      1.1  christos 
    256  1.1.1.3  christos 		if (dlen == plen || (dlen > plen && dname[dlen - plen - 1] == '.' )) {
    257  1.1.1.2  christos 			ds = dname + (dlen - plen);
    258  1.1.1.2  christos 		}
    259  1.1.1.3  christos 		if (qlen == plen || (qlen > plen && qname[qlen - plen - 1] == '.' )) {
    260  1.1.1.2  christos 			qs = qname + (qlen - plen);
    261  1.1.1.2  christos 		}
    262  1.1.1.2  christos 		if ((ds && strncasecmp(p->str, ds, plen) == 0)
    263  1.1.1.2  christos 			|| (qs && strncasecmp(p->str, qs, plen) == 0)) {
    264  1.1.1.2  christos 			d = (struct packed_rrset_data*)rrset->entry.data;
    265  1.1.1.4  christos 			ipset_add_rrset_data(ie, d, setname, af, dname);
    266  1.1.1.2  christos 			break;
    267      1.1  christos 		}
    268      1.1  christos 	}
    269      1.1  christos 	return 0;
    270      1.1  christos }
    271      1.1  christos 
    272  1.1.1.2  christos static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
    273  1.1.1.2  christos 	struct query_info qinfo, struct ipset_env *ie)
    274  1.1.1.2  christos {
    275      1.1  christos 	size_t i;
    276      1.1  christos 	const char *setname;
    277      1.1  christos 	struct ub_packed_rrset_key *rrset;
    278      1.1  christos 	int af;
    279  1.1.1.2  christos 	static char qname[BUFF_LEN];
    280  1.1.1.2  christos 	int qlen;
    281      1.1  christos 
    282  1.1.1.4  christos #ifdef HAVE_NET_PFVAR_H
    283  1.1.1.4  christos #else
    284  1.1.1.4  christos 	if (!ie->dev) {
    285  1.1.1.2  christos 		/* retry to create mnl socket */
    286  1.1.1.4  christos 		ie->dev = open_filter();
    287  1.1.1.4  christos 		if (!ie->dev) {
    288  1.1.1.4  christos 			log_warn("ipset open_filter failed");
    289      1.1  christos 			return -1;
    290      1.1  christos 		}
    291      1.1  christos 	}
    292  1.1.1.4  christos #endif
    293      1.1  christos 
    294  1.1.1.2  christos 	qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
    295  1.1.1.2  christos 		qname, BUFF_LEN);
    296  1.1.1.2  christos 	if(qlen == 0) {
    297  1.1.1.2  christos 		log_err("bad domain name");
    298  1.1.1.2  christos 		return -1;
    299  1.1.1.2  christos 	}
    300      1.1  christos 
    301  1.1.1.2  christos 	for(i = 0; i < return_msg->rep->rrset_count; i++) {
    302  1.1.1.2  christos 		setname = NULL;
    303      1.1  christos 		rrset = return_msg->rep->rrsets[i];
    304  1.1.1.2  christos 		if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A &&
    305  1.1.1.2  christos 			ie->v4_enabled == 1) {
    306      1.1  christos 			af = AF_INET;
    307  1.1.1.2  christos 			setname = ie->name_v4;
    308  1.1.1.2  christos 		} else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA &&
    309  1.1.1.2  christos 			ie->v6_enabled == 1) {
    310      1.1  christos 			af = AF_INET6;
    311  1.1.1.2  christos 			setname = ie->name_v6;
    312      1.1  christos 		}
    313      1.1  christos 
    314      1.1  christos 		if (setname) {
    315  1.1.1.4  christos 			if(ipset_check_zones_for_rrset(env, ie, rrset, qname,
    316  1.1.1.4  christos 				qlen, setname, af) == -1)
    317      1.1  christos 				return -1;
    318      1.1  christos 		}
    319      1.1  christos 	}
    320      1.1  christos 
    321      1.1  christos 	return 0;
    322      1.1  christos }
    323      1.1  christos 
    324  1.1.1.4  christos int ipset_startup(struct module_env* env, int id) {
    325      1.1  christos 	struct ipset_env *ipset_env;
    326      1.1  christos 
    327      1.1  christos 	ipset_env = (struct ipset_env *)calloc(1, sizeof(struct ipset_env));
    328      1.1  christos 	if (!ipset_env) {
    329      1.1  christos 		log_err("malloc failure");
    330      1.1  christos 		return 0;
    331      1.1  christos 	}
    332      1.1  christos 
    333      1.1  christos 	env->modinfo[id] = (void *)ipset_env;
    334      1.1  christos 
    335  1.1.1.4  christos #ifdef HAVE_NET_PFVAR_H
    336  1.1.1.4  christos 	ipset_env->dev = open_filter();
    337  1.1.1.4  christos 	if (!ipset_env->dev) {
    338  1.1.1.4  christos 		log_err("ipset open_filter failed");
    339      1.1  christos 		return 0;
    340      1.1  christos 	}
    341  1.1.1.4  christos #else
    342  1.1.1.4  christos 	ipset_env->dev = NULL;
    343  1.1.1.4  christos #endif
    344      1.1  christos 	return 1;
    345      1.1  christos }
    346      1.1  christos 
    347  1.1.1.4  christos void ipset_destartup(struct module_env* env, int id) {
    348  1.1.1.4  christos 	filter_dev dev;
    349      1.1  christos 	struct ipset_env *ipset_env;
    350      1.1  christos 
    351      1.1  christos 	if (!env || !env->modinfo[id]) {
    352      1.1  christos 		return;
    353      1.1  christos 	}
    354  1.1.1.4  christos 	ipset_env = (struct ipset_env*)env->modinfo[id];
    355      1.1  christos 
    356  1.1.1.4  christos 	dev = (filter_dev)ipset_env->dev;
    357  1.1.1.4  christos 	if (dev) {
    358  1.1.1.4  christos #if HAVE_NET_PFVAR_H
    359  1.1.1.4  christos 		close(dev);
    360  1.1.1.4  christos #else
    361  1.1.1.4  christos 		mnl_socket_close(dev);
    362  1.1.1.4  christos #endif
    363  1.1.1.4  christos 		ipset_env->dev = NULL;
    364      1.1  christos 	}
    365      1.1  christos 
    366      1.1  christos 	free(ipset_env);
    367      1.1  christos 	env->modinfo[id] = NULL;
    368      1.1  christos }
    369      1.1  christos 
    370  1.1.1.4  christos int ipset_init(struct module_env* env, int id) {
    371  1.1.1.4  christos 	struct ipset_env *ipset_env = env->modinfo[id];
    372  1.1.1.4  christos 
    373  1.1.1.4  christos 	ipset_env->name_v4 = env->cfg->ipset_name_v4;
    374  1.1.1.4  christos 	ipset_env->name_v6 = env->cfg->ipset_name_v6;
    375  1.1.1.4  christos 
    376  1.1.1.4  christos 	ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
    377  1.1.1.4  christos 	ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
    378  1.1.1.4  christos 
    379  1.1.1.4  christos 	if ((ipset_env->v4_enabled < 1) && (ipset_env->v6_enabled < 1)) {
    380  1.1.1.4  christos 		log_err("ipset: set name no configuration?");
    381  1.1.1.4  christos 		return 0;
    382  1.1.1.4  christos 	}
    383  1.1.1.4  christos 
    384  1.1.1.4  christos 	return 1;
    385  1.1.1.4  christos }
    386  1.1.1.4  christos 
    387  1.1.1.4  christos void ipset_deinit(struct module_env *ATTR_UNUSED(env), int ATTR_UNUSED(id)) {
    388  1.1.1.4  christos 	/* nothing */
    389  1.1.1.4  christos }
    390  1.1.1.4  christos 
    391      1.1  christos static int ipset_new(struct module_qstate* qstate, int id) {
    392      1.1  christos 	struct ipset_qstate *iq = (struct ipset_qstate *)regional_alloc(
    393      1.1  christos 		qstate->region, sizeof(struct ipset_qstate));
    394      1.1  christos 	qstate->minfo[id] = iq;
    395      1.1  christos 	if (!iq) {
    396      1.1  christos 		return 0;
    397      1.1  christos 	}
    398      1.1  christos 
    399      1.1  christos 	memset(iq, 0, sizeof(*iq));
    400      1.1  christos 	/* initialise it */
    401      1.1  christos 	/* TODO */
    402      1.1  christos 
    403      1.1  christos 	return 1;
    404      1.1  christos }
    405      1.1  christos 
    406      1.1  christos void ipset_operate(struct module_qstate *qstate, enum module_ev event, int id,
    407      1.1  christos 	struct outbound_entry *outbound) {
    408      1.1  christos 	struct ipset_env *ie = (struct ipset_env *)qstate->env->modinfo[id];
    409      1.1  christos 	struct ipset_qstate *iq = (struct ipset_qstate *)qstate->minfo[id];
    410      1.1  christos 	verbose(VERB_QUERY, "ipset[module %d] operate: extstate:%s event:%s",
    411      1.1  christos 		id, strextstate(qstate->ext_state[id]), strmodulevent(event));
    412      1.1  christos 	if (iq) {
    413      1.1  christos 		log_query_info(VERB_QUERY, "ipset operate: query", &qstate->qinfo);
    414      1.1  christos 	}
    415      1.1  christos 
    416      1.1  christos 	/* perform ipset state machine */
    417      1.1  christos 	if ((event == module_event_new || event == module_event_pass) && !iq) {
    418      1.1  christos 		if (!ipset_new(qstate, id)) {
    419      1.1  christos 			(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
    420      1.1  christos 			return;
    421      1.1  christos 		}
    422      1.1  christos 		iq = (struct ipset_qstate*)qstate->minfo[id];
    423      1.1  christos 	}
    424      1.1  christos 
    425      1.1  christos 	if (iq && (event == module_event_pass || event == module_event_new)) {
    426      1.1  christos 		qstate->ext_state[id] = module_wait_module;
    427      1.1  christos 		return;
    428      1.1  christos 	}
    429      1.1  christos 
    430      1.1  christos 	if (iq && (event == module_event_moddone)) {
    431      1.1  christos 		if (qstate->return_msg && qstate->return_msg->rep) {
    432  1.1.1.2  christos 			ipset_update(qstate->env, qstate->return_msg, qstate->qinfo, ie);
    433      1.1  christos 		}
    434      1.1  christos 		qstate->ext_state[id] = module_finished;
    435      1.1  christos 		return;
    436      1.1  christos 	}
    437      1.1  christos 
    438      1.1  christos 	if (iq && outbound) {
    439      1.1  christos 		/* ipset does not need to process responses at this time
    440      1.1  christos 		 * ignore it.
    441      1.1  christos 		ipset_process_response(qstate, iq, ie, id, outbound, event);
    442      1.1  christos 		*/
    443      1.1  christos 		return;
    444      1.1  christos 	}
    445      1.1  christos 
    446      1.1  christos 	if (event == module_event_error) {
    447      1.1  christos 		verbose(VERB_ALGO, "got called with event error, giving up");
    448      1.1  christos 		(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
    449      1.1  christos 		return;
    450      1.1  christos 	}
    451      1.1  christos 
    452      1.1  christos 	if (!iq && (event == module_event_moddone)) {
    453      1.1  christos 		/* during priming, module done but we never started */
    454      1.1  christos 		qstate->ext_state[id] = module_finished;
    455      1.1  christos 		return;
    456      1.1  christos 	}
    457      1.1  christos 
    458      1.1  christos 	log_err("bad event for ipset");
    459      1.1  christos 	(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
    460      1.1  christos }
    461      1.1  christos 
    462      1.1  christos void ipset_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
    463      1.1  christos 	int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super)) {
    464      1.1  christos 	/* ipset does not use subordinate requests at this time */
    465      1.1  christos 	verbose(VERB_ALGO, "ipset inform_super was called");
    466      1.1  christos }
    467      1.1  christos 
    468      1.1  christos void ipset_clear(struct module_qstate *qstate, int id) {
    469      1.1  christos 	struct cachedb_qstate *iq;
    470      1.1  christos 	if (!qstate) {
    471      1.1  christos 		return;
    472      1.1  christos 	}
    473      1.1  christos 	iq = (struct cachedb_qstate *)qstate->minfo[id];
    474      1.1  christos 	if (iq) {
    475      1.1  christos 		/* free contents of iq */
    476      1.1  christos 		/* TODO */
    477      1.1  christos 	}
    478      1.1  christos 	qstate->minfo[id] = NULL;
    479      1.1  christos }
    480      1.1  christos 
    481      1.1  christos size_t ipset_get_mem(struct module_env *env, int id) {
    482      1.1  christos 	struct ipset_env *ie = (struct ipset_env *)env->modinfo[id];
    483      1.1  christos 	if (!ie) {
    484      1.1  christos 		return 0;
    485      1.1  christos 	}
    486      1.1  christos 	return sizeof(*ie);
    487      1.1  christos }
    488      1.1  christos 
    489      1.1  christos /**
    490      1.1  christos  * The ipset function block
    491      1.1  christos  */
    492      1.1  christos static struct module_func_block ipset_block = {
    493      1.1  christos 	"ipset",
    494  1.1.1.4  christos 	&ipset_startup, &ipset_destartup, &ipset_init, &ipset_deinit,
    495  1.1.1.4  christos 	&ipset_operate, &ipset_inform_super, &ipset_clear, &ipset_get_mem
    496      1.1  christos };
    497      1.1  christos 
    498      1.1  christos struct module_func_block * ipset_get_funcblock(void) {
    499      1.1  christos 	return &ipset_block;
    500      1.1  christos }
    501      1.1  christos 
    502