]> git.ipfire.org Git - zone-sync.git/commitdiff
main: Build out fetching zone data
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 11 May 2026 14:05:57 +0000 (14:05 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 11 May 2026 14:05:57 +0000 (14:05 +0000)
This is just about working, but needs a lot more to be robust.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
main.c

diff --git a/main.c b/main.c
index b3120b9d894e77978dd7559d99f94b53dcf09ea5..f712534bb3be8054b9d36d3df6e65942b34253ba 100644 (file)
--- a/main.c
+++ b/main.c
 #include <stdio.h>
 #include <syslog.h>
 
+#include <urcu/rculist.h>
 #include <urcu/wfcqueue.h>
+#include <urcu/call-rcu.h>
 
+#include <dns/dispatch.h>
+#include <dns/view.h>
+#include <dns/xfrin.h>
+#include <dns/zone.h>
 #include <isc/log.h>
 #include <isc/loop.h>
 #include <isc/mem.h>
 #include <isc/netmgr.h>
+#include <isc/tls.h>
 
 #define DEFAULT_PATH   "/tmp"
 
@@ -52,6 +59,18 @@ typedef struct ctx {
 
        // Network Manager
        isc_nm_t* netmgr;
+
+       // Zone Manager
+       dns_zonemgr_t* zonemgr;
+
+       // Dispatch Manager
+       dns_dispatchmgr_t* dispatchmgr;
+
+       // View
+       dns_view_t* view;
+
+       // TLS Context Cache
+       isc_tlsctx_cache_t* tlsctx_cache;
 } ctx_t;
 
 // Create the context
@@ -132,25 +151,233 @@ static void setup_logging(void) {
        /* Tell libdns to register its categories/modules
        * with this log context, and use it as default */
        dns_log_init(ctx.log);
-       dns_log_setcontext(ctx.log);
+       //dns_log_setcontext(ctx.log);
 
        /* Also make libisc itself use it */
        isc_log_setcontext(ctx.log);
 }
 
-static void do_zone(ctx_t* ctx, const char* name) {
-       DEBUG(ctx, "Processing zone %s\n", name);
+static void transfer_done(dns_zone_t* zone, uint32_t* serial, isc_result_t result) {
+       int r;
+
+       switch (result) {
+               case ISC_R_SUCCESS:
+                       DEBUG("Transfer successful\n");
+
+                       // Commit any changes
+                       r = dns_zone_flush(zone);
+                       if (r) {
+                               ERROR("Failed to flush zone\n");
+                       }
+                       break;
+
+               case DNS_R_UPTODATE:
+                       DEBUG("Zone is up to date\n");
+                       break;
+
+               default:
+                       ERROR("Zone transfer failed\n");
+                       break;
+       }
+
+       // Release the zone from the manager
+    dns_zonemgr_releasezone(ctx.zonemgr, zone);
 
-       // XXX TODO
+       // Free the zone
+    dns_zone_detach(&zone);
+}
+
+static int do_transfer(dns_zone_t* zone, uint32_t serial) {
+       dns_xfrin_t* xfrin = NULL;
+    isc_sockaddr_t primary;
+       dns_rdatatype_t xfrtype;
+
+       // Try an incremental xfr if we have a serial
+       if (serial) {
+               DEBUG("Zone is at serial %d, trying IXFR\n", serial);
+               xfrtype = dns_rdatatype_soa;
+
+       // Otherwise force AXFR
+       } else {
+               DEBUG("No serial for zone, doing AXFR\n");
+               xfrtype = dns_rdatatype_axfr;
+       }
+
+    struct in_addr a;
+    inet_pton(AF_INET, "81.3.27.55", &a);
+    isc_sockaddr_fromin(&primary, &a, 53);
+
+       isc_sockaddr_t source;
+       struct in_addr any = { .s_addr = INADDR_ANY };
+       isc_sockaddr_fromin(&source, &any, 0);
+
+       // Require at least 10 kBit/s to be transmitted over 5 minutes
+       dns_zone_setminxfrratein(zone, 10240, 300);
+
+       dns_xfrin_create(zone, xfrtype, &primary, &source, NULL,
+               DNS_TRANSPORT_NONE, NULL, ctx.tlsctx_cache, ctx.memctx, &xfrin);
+
+       // Start the transfer
+       return dns_xfrin_start(xfrin, transfer_done);
+}
+
+static isc_result_t zone_loaded(void* data) {
+       dns_zone_t* zone = data;
+       uint32_t serial = 0;
+       int r;
+
+       // Fetch the serial
+       r = dns_zone_getserial(zone, &serial);
+       switch (r) {
+               case ISC_R_SUCCESS:
+                       DEBUG("Zone loaded from %s with serial %d\n", dns_zone_getfile(zone), serial);
+                       break;
+
+               case DNS_R_NOTLOADED:
+                       DEBUG("Could not load zone from %s\n", dns_zone_getfile(zone));
+                       break;
+
+               default:
+                       ERROR("Failed to load zone from %s\n", dns_zone_getfile(zone));
+                       goto ERROR;
+       }
+
+       // Initiate the transfer
+       return do_transfer(zone, serial);
+
+ERROR:
+       // Free the zone
+       dns_zone_detach(&zone);
+
+       return r;
+}
+
+static void do_zone(const char* name) {
+       dns_fixedname_t fixed = {};
+       dns_name_t* origin = NULL;
+       dns_zone_t* zone = NULL;
+       isc_buffer_t buffer;
+       char path[PATH_MAX];
+       int r;
+
+       // Create the origin
+       origin = dns_fixedname_initname(&fixed);
+
+       isc_buffer_constinit(&buffer, name, strlen(name));
+       isc_buffer_add(&buffer, strlen(name));
+
+       dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL);
+
+       DEBUG("Processing zone %s\n", name);
+
+       // Compose the path for the zone
+       r = snprintf(path, sizeof(path), "%s/%s.zone", ctx.path, name);
+       if (r < 0) {
+               ERROR("Failed to make path to zone: %m\n");
+               goto ERROR;
+       }
+
+       // Create a new zone
+       dns_zone_create(&zone, ctx.memctx, 0);
+
+       // Manage the zone through the zone manager
+       r = dns_zonemgr_managezone(ctx.zonemgr, zone);
+       if (r) {
+               ERROR("Failed to add the zone to the zone manager: %s\n", isc_result_totext(r));
+               goto ERROR;
+       }
+
+       // Set the zone's origin
+       r = dns_zone_setorigin(zone, origin);
+       if (r) {
+               ERROR("Failed to set the zone's origin\n");
+               goto ERROR;
+       }
+
+       // We treat this as a secondary zone
+       dns_zone_settype(zone, dns_zone_secondary);
+
+       // Set the class
+       dns_zone_setclass(zone, dns_rdataclass_in);
+
+       // Set the filename of the zone
+       r = dns_zone_setfile(zone, path, dns_masterformat_text, &dns_master_style_default);
+       if (r) {
+               ERROR("Failed to set the zone's filename %s: %m\n", path);
+               goto ERROR;
+       }
+
+       // Attach view to the zone
+       dns_zone_setview(zone, ctx.view);
+
+       // Load the zone from file
+       r = dns_zone_asyncload(zone, 0, zone_loaded, zone);
+       switch (r) {
+               case ISC_R_SUCCESS:
+                       break;
+
+               default:
+                       ERROR("Failed to load zone: %s\n", isc_result_totext(r));
+                       break;
+       }
+
+       // Done
+       return;
+
+ERROR:
+       // Destroy the zone
+       dns_zone_detach(&zone);
+
+       return;
 }
 
 static void run_loop(void* data) {
+       int r;
+
        DEBUG("Event loop started\n");
 
+       // Create a new dispatch manager
+       dns_dispatchmgr_create(ctx.memctx, ctx.loopmgr, ctx.netmgr, &ctx.dispatchmgr);
+
+       // Create a zone manager
+       dns_zonemgr_create(ctx.memctx, ctx.netmgr, &ctx.zonemgr);
+
+       // Create a view
+       r = dns_view_create(ctx.memctx, ctx.loopmgr, ctx.dispatchmgr,
+                       dns_rdataclass_in, "default", &ctx.view);
+       if (r) {
+               ERROR("Failed to create view: %s\n", isc_result_totext(r));
+               goto ERROR;
+       }
+
        // Process all zones
-       for (unsigned int i = 0; i < ctx.num_zones; i++) {
+       for (unsigned int i = 0; i < ctx.num_zones; i++)
                do_zone(ctx.zones[i]);
+
+       // Done
+       return;
+
+ERROR:
+       // Shutdown the event loop on error
+       isc_loopmgr_shutdown(ctx.loopmgr);
+}
+
+static void destroy_loop(void* data) {
+       DEBUG("Destroying event loop\n");
+
+       // Destroy the view
+       if (ctx.view)
+               dns_view_detach(&ctx.view);
+
+       // Destroy the zone manager
+       if (ctx.zonemgr) {
+               dns_zonemgr_shutdown(ctx.zonemgr);
+               dns_zonemgr_detach(&ctx.zonemgr);
        }
+
+       // Detach the dispatch manager
+       if (ctx.dispatchmgr)
+               dns_dispatchmgr_detach(&ctx.dispatchmgr);
 }
 
 const char* argp_program_version = PACKAGE_VERSION;
@@ -236,22 +463,29 @@ int main(int argc, char* argv[]) {
        // Setup logging
        setup_logging();
 
+       // Create the TLS context cache
+       isc_tlsctx_cache_create(ctx.memctx, &ctx.tlsctx_cache);
+
        // Initialize the loop manager
        isc_loopmgr_create(ctx.memctx, 1, &ctx.loopmgr);
 
        // Create a new netmgr
        isc_netmgr_create(ctx.memctx, ctx.loopmgr, &ctx.netmgr);
 
-       // Register a callback to be called when the loop starts
+       // Register a callback to be called when the loop starts/finishes
        isc_loopmgr_setup(ctx.loopmgr, run_loop, &ctx);
+       isc_loopmgr_teardown(ctx.loopmgr, destroy_loop, &ctx);
 
        // Run the event loop
        isc_loopmgr_run(ctx.loopmgr);
 
 ERROR:
-       isc_netmgr_destroy(&ctx.netmgr);
-       isc_loopmgr_destroy(&ctx.loopmgr);
-
+       if (ctx.netmgr)
+               isc_netmgr_destroy(&ctx.netmgr);
+       if (ctx.loopmgr)
+               isc_loopmgr_destroy(&ctx.loopmgr);
+       if (ctx.tlsctx_cache)
+               isc_tlsctx_cache_detach(&ctx.tlsctx_cache);
        if (ctx.zones)
                free(ctx.zones);