#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"
// 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
/* 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;
// 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);