/*
* Copyright (C) 2017 Aaron M. D. Jones <aaronmdjones@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "acopm-common.h"
#include <assert.h> /* assert() */
#include <errno.h> /* errno */
#include <string.h> /* strerror() */
#include <event2/dns.h> /* evdns_*() */
#include <event2/event.h> /* struct event_base */
#include "3rdparty/utlist.h" /* DL_FOREACH_SAFE() */
#include "dnsbl/client.h" /* decls for own functions */
#include "dnsbl/lookup.h" /* ACOPM_DNSBL_LOOKUP_* */
#include "dnsbl/internal.h" /* internal decls */
#include "utils/log.h" /* acopm_log_*() */
struct acopm_dnsbl_client *
acopm_dnsbl_new(struct event_base *const restrict ev_base)
{
assert(ev_base != NULL);
struct acopm_dnsbl_client *const client = calloc(1, sizeof *client);
if (! client)
{
(void) acopm_log_error("%s: calloc: %s", __func__, strerror(errno));
return NULL;
}
if (! (client->ev_base = evdns_base_new(ev_base, 0)))
{
(void) acopm_log_error("%s: evdns_base_new: %s", __func__, strerror(errno));
(void) acopm_dnsbl_free(client);
return NULL;
}
(void) acopm_log_debug("%s: created client", __func__);
return client;
}
bool
acopm_dnsbl_set_timeout(struct acopm_dnsbl_client *const restrict client, const unsigned int lookup_timeout)
{
assert(client != NULL);
assert(client->ev_base != NULL);
assert((lookup_timeout >= ACOPM_DNSBL_LOOKUP_TIMEOUT_MIN) && (lookup_timeout <= ACOPM_DNSBL_LOOKUP_TIMEOUT_MAX));
char timeout_str[32];
(void) snprintf(timeout_str, sizeof timeout_str, "%u", lookup_timeout);
if (evdns_base_set_option(client->ev_base, "timeout:", timeout_str) == -1)
{
(void) acopm_log_warning("%s: unable to set lookup timeout", __func__);
return false;
}
(void) acopm_log_debug("%s: lookup timeout set to %u", __func__, lookup_timeout);
return true;
}
bool
acopm_dnsbl_add_nameserver(struct acopm_dnsbl_client *const restrict client, const char *const restrict nameserver)
{
assert(client != NULL);
assert(nameserver != NULL);
assert(*nameserver != 0x00);
(void) acopm_log_debug("%s: adding nameserver %s", __func__, nameserver);
if (evdns_base_nameserver_ip_add(client->ev_base, nameserver) != 0)
{
(void) acopm_log_error("%s: nameserver_ip_add: %s", __func__, strerror(errno));
return false;
}
client->ready = true;
return true;
}
void
acopm_dnsbl_free(struct acopm_dnsbl_client *const restrict client)
{
assert(client != NULL);
(void) acopm_log_debug("%s: freeing client", __func__);
if (client->lookups)
{
struct acopm_dnsbl_lookup *lookup, *tmp;
DL_FOREACH_SAFE(client->lookups, lookup, tmp)
{
if (! client->lookups)
break;
(void) acopm_dnsbl_lookup_free(lookup);
}
}
if (client->domains)
{
struct acopm_dnsbl_domain *domain, *tmp;
DL_FOREACH_SAFE(client->domains, domain, tmp)
{
if (! client->domains)
break;
(void) acopm_dnsbl_domain_free(domain);
}
}
if (client->ev_base)
(void) evdns_base_free(client->ev_base, 0);
(void) free(client);
}