/*
- * itkacl control library, version 0.1
+ * ITKACL control library.
*
- * (C) 2004-2009 Steinar H. Gunderson
+ * (C) 2004-2013 Steinar H. Gunderson
* GPL, v2.
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
-#include <netdb.h>
+#include <unbound.h>
struct itkacl_config {
char nszone[256];
+ int require_dnssec;
+ char dnssec_public_key[256];
};
#define CONFIG_FILENAME "/etc/itkacl.conf"
FILE *fp;
int lineno = 0;
+ /* Defaults. */
strcpy(config->nszone, "");
+ config->require_dnssec = 0;
+ strcpy(config->dnssec_public_key, "");
fp = fopen(CONFIG_FILENAME, "r");
if (fp == NULL) {
strcpy(config->nszone, arg);
continue;
}
+ if (strcmp(line, "require-dnssec") == 0) {
+ config->require_dnssec = 1;
+ continue;
+ }
+ if (sscanf(line, "dnssec-public-key %255s", arg) == 1) {
+ strcpy(config->dnssec_public_key, arg);
+ continue;
+ }
if (errmsg)
snprintf(errmsg, errmsg_size, "%s: Could not parse line %d",
char *errmsg, size_t errmsg_size)
{
struct itkacl_config config;
- struct hostent he, *he_ptr;
- int ret, host_errno;
+ int ret, nxdomain;
const char *ptr;
char nszone[256];
- char temp[256], ns_temp[1024];
+ char temp[256];
+ struct ub_ctx* ctx;
+ struct ub_result* result;
if (itkacl_read_config(CONFIG_FILENAME, &config, errmsg, errmsg_size) != 0) {
return -1;
strcpy(temp, nszone);
sprintf(nszone, "%s.%s", user, temp);
- ret = gethostbyname_r(nszone, &he, ns_temp, 1024, &he_ptr, &host_errno);
+ /* Create the DNS resolver context. */
+ ctx = ub_ctx_create();
+ if (ctx == NULL) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size, "Host name lookup failure: Could not create DNS context");
+ return -1;
+ }
- /*
- * The man page for gethostbyname_r() specifies ret != 0 on failure, but
- * that seemingly does not include HOST_NOT_FOUND failure.
- */
- if (he_ptr == NULL) {
- // Not found => no access, but no error either.
- if (host_errno == HOST_NOT_FOUND) {
- return 1;
- }
+ ret = ub_ctx_resolvconf(ctx, NULL);
+ if (ret != 0) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size,
+ "Host name lookup failure: Could not read resolv.conf "
+ "(resolver error: %s) (system error: %s)",
+ ub_strerror(ret), strerror(errno));
+ ub_ctx_delete(ctx);
+ return -1;
+ }
- switch (host_errno) {
- case TRY_AGAIN:
- snprintf(errmsg, errmsg_size, "Host name lookup failure");
- break;
- case NO_RECOVERY:
- snprintf(errmsg, errmsg_size, "Unknown server error");
- break;
- case NO_ADDRESS:
- snprintf(errmsg, errmsg_size, "No address associated with name");
- break;
- default:
- snprintf(errmsg, errmsg_size, "Unknown DNS error %d", host_errno);
+ ret = ub_ctx_hosts(ctx, NULL);
+ if (ret != 0) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size,
+ "Host name lookup failure: Could not read hosts file "
+ "(resolver error: %s) (system error: %s)",
+ ub_strerror(ret), strerror(errno));
+ ub_ctx_delete(ctx);
+ return -1;
+ }
+
+ if (strlen(config.dnssec_public_key) != 0) {
+ ret = ub_ctx_add_ta_file(ctx, config.dnssec_public_key);
+ if (ret != 0) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size,
+ "Host name lookup failure: Error adding keys from %s "
+ "(resolver error: %s) (system error: %s)",
+ config.dnssec_public_key,
+ ub_strerror(ret), strerror(errno));
+ ub_ctx_delete(ctx);
+ return -1;
}
+ }
+
+ /* Do the actual DNS lookup (TYPE A, CLASS IN). */
+ ret = ub_resolve(ctx, nszone, 1, 1, &result);
+ if (ret != 0) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size, "Host name lookup failure: %s",
+ ub_strerror(ret));
+ ub_ctx_delete(ctx);
return -1;
}
- // The lookup succeeded, so we're good.
- return 0;
+ /* Verify DNSSEC. */
+ if (result->bogus) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size,
+ "Host name lookup failure: Bogus DNSSEC result (security failure)");
+ ub_resolve_free(result);
+ ub_ctx_delete(ctx);
+ return -1;
+ }
+ if (config.require_dnssec && !result->secure) {
+ if (errmsg)
+ snprintf(errmsg, errmsg_size,
+ "Host name lookup failure: Result was not secured with DNSSEC");
+ ub_resolve_free(result);
+ ub_ctx_delete(ctx);
+ return -1;
+ }
+
+ nxdomain = result->nxdomain;
+
+ ub_resolve_free(result);
+ ub_ctx_delete(ctx);
+
+ if (nxdomain)
+ return 1;
+ else
+ return 0;
}