Add an API for keeping a permanent library context, for performance reasons
authorSteinar H. Gunderson <sesse@samfundet.no>
Tue, 15 Mar 2022 21:01:39 +0000 (22:01 +0100)
committerSteinar H. Gunderson <sesse@samfundet.no>
Tue, 15 Mar 2022 21:45:35 +0000 (22:45 +0100)
(unbound in buster and newer needs a lot of CU time for creating a new DNS
context).

19 files changed:
itkacl-2.1/itkacl-test.c [deleted file]
itkacl-2.1/itkacl.h [deleted file]
itkacl-2.2/Makefile [moved from itkacl-2.1/Makefile with 97% similarity]
itkacl-2.2/config.pm [moved from itkacl-2.1/config.pm with 100% similarity]
itkacl-2.2/debian/changelog [moved from itkacl-2.1/debian/changelog with 63% similarity]
itkacl-2.2/debian/compat [moved from itkacl-2.1/debian/compat with 100% similarity]
itkacl-2.2/debian/control [moved from itkacl-2.1/debian/control with 100% similarity]
itkacl-2.2/debian/copyright [moved from itkacl-2.1/debian/copyright with 100% similarity]
itkacl-2.2/debian/itkacl-sync.dirs [moved from itkacl-2.1/debian/itkacl-sync.dirs with 100% similarity]
itkacl-2.2/debian/itkacl-sync.install [moved from itkacl-2.1/debian/itkacl-sync.install with 100% similarity]
itkacl-2.2/debian/libitkacl-dev.install [moved from itkacl-2.1/debian/libitkacl-dev.install with 100% similarity]
itkacl-2.2/debian/libitkacl2.install [moved from itkacl-2.1/debian/libitkacl2.install with 100% similarity]
itkacl-2.2/debian/rules [moved from itkacl-2.1/debian/rules with 100% similarity]
itkacl-2.2/itkacl-test.c [new file with mode: 0644]
itkacl-2.2/itkacl.c [moved from itkacl-2.1/itkacl.c with 76% similarity]
itkacl-2.2/itkacl.conf [moved from itkacl-2.1/itkacl.conf with 100% similarity]
itkacl-2.2/itkacl.h [new file with mode: 0644]
itkacl-2.2/itkacl.sql [moved from itkacl-2.1/itkacl.sql with 100% similarity]
itkacl-2.2/sync-itkacl.pl [moved from itkacl-2.1/sync-itkacl.pl with 100% similarity]

diff --git a/itkacl-2.1/itkacl-test.c b/itkacl-2.1/itkacl-test.c
deleted file mode 100644 (file)
index 49388d4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <stdio.h>
-
-int itkacl_check(const char * const realm, const char * const user,
-               char *errmsg, size_t errmsg_size);
-       
-int main()
-{
-       char errmsg[1024];
-       int ret = itkacl_check("/login/unix-servers/cirkus", "sesse", errmsg, sizeof(errmsg));
-
-       if (ret == 0) {
-               printf("OK\n");
-       } else if (ret == -1) {
-               printf("Error: %s\n", errmsg);
-       } else {
-               printf("Not OK\n");
-       }
-       return 0;
-}
diff --git a/itkacl-2.1/itkacl.h b/itkacl-2.1/itkacl.h
deleted file mode 100644 (file)
index 32d94a7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _ITKACL_H
-#define _ITKACL_H
-
-/*
- * itkacl control library, version 0.1
- *
- * (C) 2004-2009 Steinar H. Gunderson
- * GPL, v2.
- */
-
-int itkacl_check(const char * const realm, const char * const user,
-                char *errmsg, size_t errmsg_size);
-
-#endif  /* !defined(_ITKACL_H) */
similarity index 97%
rename from itkacl-2.1/Makefile
rename to itkacl-2.2/Makefile
index 99ef295e0fa49d9970feccd79f3477386a65af79..029de705ab9c0cd4300e57cff3375b86303f91d4 100644 (file)
@@ -6,7 +6,7 @@ RANLIB=ranlib
 PREFIX=/usr/local
 
 SONAME=libitkacl.so.2
-LIBNAME=libitkacl.so.2.0.0
+LIBNAME=libitkacl.so.2.0.1
 
 all: libitkacl.a $(LIBNAME) itkacl-test
 clean:
similarity index 100%
rename from itkacl-2.1/config.pm
rename to itkacl-2.2/config.pm
similarity index 63%
rename from itkacl-2.1/debian/changelog
rename to itkacl-2.2/debian/changelog
index cf405bfa203cb3b9c0f902f7cf6c87af16f3171b..601f816055a5cc911e87ab8d64d544c8b42552e9 100644 (file)
@@ -1,3 +1,11 @@
+itkacl (2.2) unstable; urgency=medium
+
+  * Add an API for keeping a permanent library context, for performance reasons
+    (unbound in buster and newer needs a lot of CU time for creating a new DNS
+    context).
+
+ -- Steinar H. Gunderson <sesse@samfundet.no>  Tue, 15 Mar 2022 21:59:20 +0100
+
 itkacl (2.1) unstable; urgency=low
 
   * Make the core library support a configuration file (/etc/itkacl.conf),
diff --git a/itkacl-2.2/itkacl-test.c b/itkacl-2.2/itkacl-test.c
new file mode 100644 (file)
index 0000000..88d2777
--- /dev/null
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include "itkacl.h"
+
+int main()
+{
+       char errmsg[1024];
+       int ret;
+       struct itkacl_ctx *ctx;
+
+       ctx = itkacl_create_ctx(errmsg, sizeof(errmsg));
+       if (ctx == NULL) {
+               printf("Error while creating context: %s\n", errmsg);
+               return 1;
+       }
+
+       ret = itkacl_check_with_ctx(ctx, "/login/unix-servers/cirkus", "sesse", errmsg, sizeof(errmsg));
+
+       itkacl_free_ctx(ctx);
+
+       if (ret == 0) {
+               printf("OK\n");
+       } else if (ret == -1) {
+               printf("Error: %s\n", errmsg);
+       } else {
+               printf("Not OK\n");
+       }
+       return 0;
+}
similarity index 76%
rename from itkacl-2.1/itkacl.c
rename to itkacl-2.2/itkacl.c
index eda3ebb70dbe00694a87d3d23f0d1abe9b5717e8..d7bdfa016c06bc37225628cda3b098f2c62d317a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ITKACL control library.
  *
- * (C) 2004-2013 Steinar H. Gunderson
+ * (C) 2004-2022 Steinar H. Gunderson
  * GPL, v2.
  */
 #include <stdio.h>
 #include <ctype.h>
 #include <unbound.h>
 
+#include "itkacl.h"
+
 struct itkacl_config {
        char nszone[256];
        int require_dnssec;
        char dnssec_public_key[256];
 };
 
+struct itkacl_ctx {
+       struct itkacl_config config;
+       struct ub_ctx *ubctx;
+};
+
 #define CONFIG_FILENAME "/etc/itkacl.conf"
 
 static int itkacl_read_config(const char * const filename,
@@ -106,18 +113,105 @@ static int itkacl_read_config(const char * const filename,
 int itkacl_check(const char * const realm, const char * const user,
                 char *errmsg, size_t errmsg_size)
 {
-       struct itkacl_config config;
+       struct itkacl_ctx *ctx;
+       int err;
+
+       ctx = itkacl_create_ctx(errmsg, errmsg_size);
+       if (ctx == NULL) {
+               return -1;
+       }
+
+       err = itkacl_check_with_ctx(ctx, realm, user, errmsg, errmsg_size);
+
+       itkacl_free_ctx(ctx);
+
+       return err;
+}
+
+struct itkacl_ctx *itkacl_create_ctx(char *errmsg, size_t errmsg_size)
+{
+       struct itkacl_ctx *ctx;
+       int ret;
+
+       ctx = (struct itkacl_ctx *)malloc(sizeof(struct itkacl_ctx));
+       if (ctx == NULL) {
+               if (errmsg)
+                       snprintf(errmsg, errmsg_size, "Memory allocation failed");
+               return NULL;
+       }
+
+       if (itkacl_read_config(CONFIG_FILENAME, &ctx->config, errmsg, errmsg_size) != 0) {
+               free(ctx);
+               return NULL;
+       }
+
+       /* Create the DNS resolver context. */
+       ctx->ubctx = ub_ctx_create();
+       if (ctx->ubctx == NULL) {
+               if (errmsg)
+                       snprintf(errmsg, errmsg_size, "Host name lookup failure: Could not create DNS context");
+               free(ctx);
+               return NULL;
+       }
+
+       ret = ub_ctx_resolvconf(ctx->ubctx, 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->ubctx);
+               free(ctx);
+               return NULL;
+       }
+
+       ret = ub_ctx_hosts(ctx->ubctx, 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->ubctx);
+               free(ctx);
+               return NULL;
+       }
+
+       if (strlen(ctx->config.dnssec_public_key) != 0) {
+               ret = ub_ctx_add_ta_file(ctx->ubctx, 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)",
+                                        ctx->config.dnssec_public_key,
+                                        ub_strerror(ret), strerror(errno));
+                       ub_ctx_delete(ctx->ubctx);
+                       free(ctx);
+                       return NULL;
+               }
+       }
+
+       return ctx;
+}
+
+void itkacl_free_ctx(struct itkacl_ctx *ctx)
+{
+       ub_ctx_delete(ctx->ubctx);
+       free(ctx);
+}
+
+int itkacl_check_with_ctx(struct itkacl_ctx *ctx,
+                          const char * const realm, const char * const user,
+                         char *errmsg, size_t errmsg_size)
+{
        int ret, nxdomain;
        const char *ptr;
        char nszone[256];
        char temp[256];
-       struct ub_ctx* ctx;
        struct ub_result* result;
 
-       if (itkacl_read_config(CONFIG_FILENAME, &config, errmsg, errmsg_size) != 0) {
-               return -1;
-       }
-
        if (realm[0] != '/') {
                if (errmsg)
                        snprintf(errmsg, errmsg_size, "Invalid realm '%s' (missing leading /)",
@@ -155,7 +249,7 @@ int itkacl_check(const char * const realm, const char * const user,
 
        /* traverse the realm entry by entry from the root,
         * creating a DNS zone name as we go */
-       strcpy(nszone, config.nszone);
+       strcpy(nszone, ctx->config.nszone);
        ptr = realm;
        while (*ptr) {
                /* copy all characters to next / or end of string */
@@ -187,57 +281,12 @@ int itkacl_check(const char * const realm, const char * const user,
        strcpy(temp, nszone);
        sprintf(nszone, "%s.%s", user, temp);
 
-       /* 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;
-       }
-
-       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;
-       }
-
-       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);
+       ret = ub_resolve(ctx->ubctx, 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;
        }
 
@@ -247,22 +296,19 @@ int itkacl_check(const char * const realm, const char * const user,
                        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 (ctx->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;
diff --git a/itkacl-2.2/itkacl.h b/itkacl-2.2/itkacl.h
new file mode 100644 (file)
index 0000000..77be702
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _ITKACL_H
+#define _ITKACL_H
+
+/*
+ * itkacl control library, version 2.2
+ *
+ * (C) 2004-2022 Steinar H. Gunderson
+ * GPL, v2.
+ */
+
+int itkacl_check(const char * const realm, const char * const user,
+                char *errmsg, size_t errmsg_size);
+
+/*
+ * Opaque context. A context is created with itkacl_create_ctx()
+ * and freed with itkacl_free_ctx(), and is thread-safe.
+ * If you are making multiple calls to itkacl_check(), it is faster
+ * to reuse the same context over and over (since libunbound can
+ * have rather high setup times depending on configuration).
+ *
+ * Configuration is only reread when the context is created.
+ */
+struct itkacl_ctx;
+
+struct itkacl_ctx *itkacl_create_ctx(char *errmsg, size_t errmsg_size);  // Returns NULL on failure.
+void itkacl_free_ctx(struct itkacl_ctx *ctx);
+
+int itkacl_check_with_ctx(struct itkacl_ctx *ctx,
+                          const char * const realm, const char * const user,
+                         char *errmsg, size_t errmsg_size);
+
+#endif  /* !defined(_ITKACL_H) */
similarity index 100%
rename from itkacl-2.1/itkacl.sql
rename to itkacl-2.2/itkacl.sql