From 09531e6df3491cebbb415722b2612545b30ec3b9 Mon Sep 17 00:00:00 2001 From: Lubos Slovak <lubos.slovak@nic.cz> Date: Tue, 2 Aug 2011 11:19:12 +0200 Subject: [PATCH] Removed zones.h include from nameserver. refs #1087 @5h --- src/knot/main.c | 3 +- src/knot/other/debug.h | 9 + src/knot/server/name-server.c | 864 +++++----------------------------- src/knot/server/name-server.h | 78 ++- src/knot/server/notify.c | 144 +++++- src/knot/server/notify.h | 41 +- src/knot/server/tcp-handler.c | 5 +- src/knot/server/udp-handler.c | 25 +- src/knot/server/xfr-handler.c | 81 +++- src/knot/server/xfr-in.c | 14 +- src/knot/server/zones.c | 356 ++++++++++++++ src/knot/server/zones.h | 33 ++ 12 files changed, 795 insertions(+), 858 deletions(-) diff --git a/src/knot/main.c b/src/knot/main.c index 640d2276b..fcfb12a4e 100644 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -11,6 +11,7 @@ #include "knot/conf/conf.h" #include "knot/conf/logconf.h" #include "common/evqueue.h" +#include "knot/server/zones.h" /*----------------------------------------------------------------------------*/ @@ -115,7 +116,7 @@ int main(int argc, char **argv) // Initialize configuration conf_read_lock(); conf_add_hook(conf(), CONF_LOG, log_conf_hook, 0); - conf_add_hook(conf(), CONF_LOG, dnslib_ns_conf_hook, server->nameserver); + conf_add_hook(conf(), CONF_LOG, zones_ns_conf_hook, server->nameserver); conf_add_hook(conf(), CONF_LOG, server_conf_hook, server); conf_read_unlock(); diff --git a/src/knot/other/debug.h b/src/knot/other/debug.h index 43024a54a..cff353d09 100644 --- a/src/knot/other/debug.h +++ b/src/knot/other/debug.h @@ -23,6 +23,15 @@ //#define NET_DEBUG //#define ZONES_DEBUG //#define XFR_DEBUG +//#define NOTIFY_DEBUG + +#ifdef NOTIFY_DEBUG +#define debug_notify(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define debug_notify_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define debug_notify(msg...) +#define debug_notify_hex(data, len) +#endif #ifdef SERVER_DEBUG #define debug_server(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) diff --git a/src/knot/server/name-server.c b/src/knot/server/name-server.c index 05fd3eb41..6b9178867 100644 --- a/src/knot/server/name-server.c +++ b/src/knot/server/name-server.c @@ -11,7 +11,7 @@ //#include "knot/stat/stat.h" //#include "knot/other/error.h" -#include "knot/server/zones.h" +//#include "knot/server/zones.h" #include "knot/server/name-server.h" #include "knot/server/notify.h" @@ -2131,17 +2131,17 @@ static int ns_ixfr_put_changeset(dnslib_ns_xfr_t *xfr, const xfrin_changeset_t * /*----------------------------------------------------------------------------*/ -static int ns_ixfr_from_zone(const dnslib_zone_t *zone, dnslib_ns_xfr_t *xfr) +static int ns_ixfr_from_zone(dnslib_ns_xfr_t *xfr) { - assert(zone != NULL); assert(xfr != NULL); + assert(xfr->zone != NULL); assert(xfr->query != NULL); assert(xfr->response != NULL); assert(dnslib_packet_additional_rrset_count(xfr->query) > 0); const dnslib_rrset_t *zone_soa = dnslib_node_rrset(dnslib_zone_contents_apex( - dnslib_zone_contents(zone)), + dnslib_zone_contents(xfr->zone)), DNSLIB_RRTYPE_SOA); // retrieve origin (xfr) serial and target (zone) serial uint32_t zone_serial = dnslib_rdata_soa_serial( @@ -2152,7 +2152,8 @@ static int ns_ixfr_from_zone(const dnslib_zone_t *zone, dnslib_ns_xfr_t *xfr) // 3) load changesets from journal xfrin_changesets_t *chgsets = (xfrin_changesets_t *) calloc(1, sizeof(xfrin_changesets_t)); - int res = xfr_load_changesets(zone, chgsets, xfr_serial, zone_serial); + int res = xfr_load_changesets(xfr->zone, chgsets, xfr_serial, + zone_serial); if (res != DNSLIB_EOK) { debug_dnslib_ns("IXFR query cannot be answered: %s.\n", dnslib_strerror(res)); @@ -2201,66 +2202,8 @@ static int ns_ixfr_from_zone(const dnslib_zone_t *zone, dnslib_ns_xfr_t *xfr) /*----------------------------------------------------------------------------*/ -static int ns_axfr(const dnslib_zonedb_t *zonedb, dnslib_ns_xfr_t *xfr) -{ - const dnslib_dname_t *qname = dnslib_packet_qname(xfr->response); - - assert(dnslib_packet_qtype(xfr->response) == DNSLIB_RRTYPE_AXFR); - -DEBUG_DNSLIB_NS( - char *name_str = dnslib_dname_to_str(qname); - debug_dnslib_ns("Trying to find zone with name %s\n", name_str); - free(name_str); -); - // find zone in which to search for the name - dnslib_zone_t *zone = dnslib_zonedb_find_zone(zonedb, qname); - - // if no zone found, return NotAuth - if (zone == NULL) { - debug_dnslib_ns("No zone found.\n"); - dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_NOTAUTH); - ns_axfr_send_and_clear(xfr); - return 1; - } - -DEBUG_DNSLIB_NS( - char *name_str2 = dnslib_dname_to_str(zone->contents->apex->owner); - debug_dnslib_ns("Found zone for QNAME %s\n", name_str2); - free(name_str2); -); - /* Check zone data. */ - zonedata_t *zd = (zonedata_t *)zone->data; - if (zd == NULL) { - debug_dnslib_ns("Invalid zone data.\n"); - dnslib_response2_set_rcode(xfr->response, - DNSLIB_RCODE_SERVFAIL); - ns_axfr_send_and_clear(xfr); - return 1; - } - - // Check xfr-out ACL - if (acl_match(zd->xfr_out, &xfr->addr) == ACL_DENY) { - debug_dnslib_ns("Request for AXFR OUT is not authorized.\n"); - dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_REFUSED); - /*! \todo Probably rename the function. */ - ns_axfr_send_and_clear(xfr); -// socket_close(xfr->session); - return 1; - } else { - debug_dnslib_ns("Authorized AXFR OUT request.\n"); - } - - // take the contents and answer from them - dnslib_zone_contents_t *contents = dnslib_zone_get_contents(zone); - - return ns_axfr_from_zone(contents, xfr); -} - -/*----------------------------------------------------------------------------*/ - -static int ns_ixfr(const dnslib_zonedb_t *zonedb, dnslib_ns_xfr_t *xfr) +static int ns_ixfr(dnslib_ns_xfr_t *xfr) { - assert(zonedb != NULL); assert(xfr != NULL); assert(xfr->query != NULL); assert(xfr->response != NULL); @@ -2294,67 +2237,7 @@ static int ns_ixfr(const dnslib_zonedb_t *zonedb, dnslib_ns_xfr_t *xfr) return 1; } - // find zone -DEBUG_DNSLIB_NS( - char *name_str = dnslib_dname_to_str(qname); - debug_dnslib_ns("Trying to find zone with name %s\n", name_str); - free(name_str); -); - // find zone in which to search for the name - dnslib_zone_t *zone = dnslib_zonedb_find_zone(zonedb, qname); - - // if no zone found, return NotAuth - if (zone == NULL) { - debug_dnslib_ns("No zone found.\n"); - dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_NOTAUTH); - ns_axfr_send_and_clear(xfr); - //socket_close(xfr->session); /*! \todo Remove for UDP. */ - return 1; - } - -DEBUG_DNSLIB_NS( - char *name_str = dnslib_dname_to_str(zone->contents->apex->owner); - debug_dnslib_ns("Found zone for QNAME %s\n", name_str); - free(name_str); -); - - /* Check zone data. */ - zonedata_t *zd = (zonedata_t *)zone->data; - if (zd == NULL) { - debug_dnslib_ns("Invalid zone data.\n"); - dnslib_response2_set_rcode(xfr->response, - DNSLIB_RCODE_SERVFAIL); - ns_axfr_send_and_clear(xfr); - //socket_close(xfr->session); /*! \todo Remove for UDP. */ - return 1; - } - - // Check xfr-out ACL - if (acl_match(zd->xfr_out, &xfr->addr) == ACL_DENY) { - debug_dnslib_ns("Request for IXFR OUT is not authorized.\n"); - dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_REFUSED); - /*! \todo Probably rename the function. */ - ns_axfr_send_and_clear(xfr); -// socket_close(xfr->session); /*! \todo Remove for UDP. */ - return 1; - } else { - debug_dnslib_ns("Authorized IXFR OUT request.\n"); - } - - // 3) call ns_ixfr_from_zone(); - return ns_ixfr_from_zone(zone, xfr); -} - -/*----------------------------------------------------------------------------*/ - -/*! - * \brief Wrapper for TCP send. - * \todo Implement generic fd pool properly with callbacks. - */ -#include "knot/server/tcp-handler.h" -static int ns_send_cb(int fd, sockaddr_t *addr, uint8_t *msg, size_t msglen) -{ - return tcp_send(fd, msg, msglen); + return ns_ixfr_from_zone(xfr); } /*----------------------------------------------------------------------------*/ @@ -2544,81 +2427,6 @@ void dnslib_ns_error_response(dnslib_nameserver_t *nameserver, uint16_t query_id /*----------------------------------------------------------------------------*/ -//int ns_answer_request(ns_nameserver_t *nameserver, const uint8_t *query_wire, -// size_t qsize, uint8_t *response_wire, size_t *rsize) -//{ -// debug_dnslib_ns("ns_answer_request() called with query size %zu.\n", qsize); -// debug_dnslib_ns_hex((char *)query_wire, qsize); - -// if (qsize < 2) { -// return DNSLIB_EMALF; -// } - -// // 1) create empty response -// debug_dnslib_ns("Parsing query using new dnslib structure...\n"); -// dnslib_response_t *resp = dnslib_response_new_empty(nameserver->opt_rr); - -// if (resp == NULL) { -// log_answer_error("Error while creating response packet!\n"); -// ns_error_response(nameserver, dnslib_wire_get_id(query_wire), -// DNSLIB_RCODE_SERVFAIL, response_wire, rsize); -// return DNSLIB_EOK; -// } - -// int ret = 0; - -// // 2) parse the query -// if ((ret = dnslib_response_parse_query(resp, query_wire, qsize)) != 0) { -// log_answer_info("Error while parsing query, " -// "dnslib error '%s'.\n", dnslib_strerror(ret)); -// ns_error_response(nameserver, dnslib_wire_get_id(query_wire), -// DNSLIB_RCODE_FORMERR, response_wire, rsize); -// dnslib_response_free(&resp); -// return DNSLIB_EOK; -// } - -// // NSID -// if (NSID_ENABLED && dnslib_response_nsid_requested(resp)) { -// (void)dnslib_response_add_nsid(resp, NSID_DATA, NSID_LENGTH); -// } - -// debug_dnslib_ns("Query parsed.\n"); -// dnslib_response_dump(resp); - -// // 3) get the answer for the query -// rcu_read_lock(); -// dnslib_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); - -// ret = ns_answer(zonedb, resp); -// if (ret != 0) { -// // now only one type of error (SERVFAIL), later maybe more -// ns_error_response(nameserver, dnslib_wire_get_id(query_wire), -// DNSLIB_RCODE_SERVFAIL, response_wire, rsize); -// } else { -// debug_dnslib_ns("Created response packet.\n"); -// dnslib_response_dump(resp); - -// // 4) Transform the packet into wire format -// if (ns_response_to_wire(resp, response_wire, rsize) != 0) { -// // send back SERVFAIL (as this is our problem) -// ns_error_response(nameserver, -// dnslib_wire_get_id(query_wire), -// DNSLIB_RCODE_SERVFAIL, response_wire, -// rsize); -// } -// } - -// dnslib_response_free(&resp); -// rcu_read_unlock(); - -// debug_dnslib_ns("Returning response with wire size %zu\n", *rsize); -// debug_dnslib_ns_hex((char *)response_wire, *rsize); - -// return DNSLIB_EOK; -//} - -/*----------------------------------------------------------------------------*/ - int dnslib_ns_answer_normal(dnslib_nameserver_t *nameserver, dnslib_packet_t *query, uint8_t *response_wire, size_t *rsize) { @@ -2725,75 +2533,9 @@ int dnslib_ns_answer_normal(dnslib_nameserver_t *nameserver, dnslib_packet_t *qu /*----------------------------------------------------------------------------*/ -int dnslib_ns_answer_notify(dnslib_nameserver_t *nameserver, dnslib_packet_t *query, - sockaddr_t *from, uint8_t *response_wire, size_t *rsize) -{ - debug_dnslib_ns("ns_answer_notify()\n"); - - /* Find matching zone from qname. */ - const dnslib_dname_t *zone_name = dnslib_packet_qname(query); - dnslib_zone_t *zone = dnslib_zonedb_find_zone(nameserver->zone_db, - zone_name); - if (!zone) { - debug_dnslib_ns("notify: matching zone not found\n"); - return DNSLIB_ENOZONE; - } - if (!dnslib_zone_data(zone)) { - debug_dnslib_ns("notify: invalid zone data\n"); - return DNSLIB_ENOZONE; - } - - /* Check ACL for notify-in. */ - zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); - if (from) { - if (acl_match(zd->notify_in, from) == ACL_DENY) { - /* rfc1996: Ignore request and report incident. */ - char straddr[SOCKADDR_STRLEN]; - sockaddr_tostr(from, straddr, sizeof(straddr)); - debug_dnslib_ns("Unauthorized NOTIFY request " - "from %s:%d.\n", - straddr, sockaddr_portnum(from)); - return DNSLIB_ERROR; - } else { - debug_dnslib_ns("notify: authorized NOTIFY query.\n"); - } - } - - /*! \todo Packet may contain updated RRs. */ - - /* Cancel EXPIRE timer. */ - evsched_t *sched = nameserver->server->sched; - event_t *expire_ev = zd->xfr_in.expire; - if (expire_ev) { - debug_dnslib_ns("notify: canceling EXPIRE timer\n"); - evsched_cancel(sched, expire_ev); - evsched_event_free(sched, expire_ev); - zd->xfr_in.expire = 0; - } - - /* Cancel REFRESH/RETRY timer. */ - event_t *refresh_ev = zd->xfr_in.timer; - if (refresh_ev) { - debug_dnslib_ns("notify: canceling REFRESH timer for XFRIN\n"); - evsched_cancel(sched, refresh_ev); - - /* Set REFRESH timer for now. */ - evsched_schedule(sched, refresh_ev, 0); - } - - /*! \todo Prepare response - copy query and set QR. */ - /*! \todo It is safe to assume response_wire contains query wire? */ - dnslib_wire_set_qr(response_wire); - *rsize = query->size; - - return DNSLIB_EOK; -} - -/*----------------------------------------------------------------------------*/ - -int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) +int dnslib_ns_init_xfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) { - debug_dnslib_ns("ns_answer_axfr()\n"); + debug_dnslib_ns("dnslib_ns_init_xfr()\n"); if (nameserver == NULL || xfr == NULL) { return DNSLIB_EBADARG; @@ -2811,8 +2553,10 @@ int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) dnslib_ns_error_response(nameserver, xfr->query->header.id, DNSLIB_RCODE_SERVFAIL, xfr->wire, &xfr->wire_size); - /*! \todo Hm, maybe send the packet? ;-) */ - return DNSLIB_EOK; + int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); + dnslib_packet_free(&response); + return res; } int ret = dnslib_packet_set_max_size(response, xfr->wire_size); @@ -2821,11 +2565,12 @@ int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) debug_dnslib_ns("Failed to init response structure.\n"); /*! \todo xfr->wire is not NULL, will fail on assert! */ dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + DNSLIB_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); dnslib_packet_free(&response); - /*! \todo Hm, maybe send the packet? ;-) */ - return DNSLIB_EOK; + return res; } ret = dnslib_response2_init_from_query(response, xfr->query); @@ -2834,28 +2579,71 @@ int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) debug_dnslib_ns("Failed to init response structure.\n"); /*! \todo xfr->wire is not NULL, will fail on assert! */ dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + DNSLIB_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); dnslib_packet_free(&response); - /*! \todo Hm, maybe send the packet? ;-) */ - return DNSLIB_EOK; + return res; } xfr->response = response; + + dnslib_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); + + const dnslib_dname_t *qname = dnslib_packet_qname(xfr->response); - // set the OPT RR to the response - /*! \todo Only if client supports it! */ - ret = dnslib_response2_add_opt(xfr->response, nameserver->opt_rr, 0); - if (ret != DNSLIB_EOK) { - debug_dnslib_ns("Failed to set OPT RR to the response: %s\n", - dnslib_strerror(ret)); + assert(dnslib_packet_qtype(xfr->response) == DNSLIB_RRTYPE_AXFR); + +DEBUG_DNSLIB_NS( + char *name_str = dnslib_dname_to_str(qname); + debug_dnslib_ns("Trying to find zone with name %s\n", name_str); + free(name_str); +); + // find zone in which to search for the name + dnslib_zone_t *zone = dnslib_zonedb_find_zone(zonedb, qname); + + // if no zone found, return NotAuth + if (zone == NULL) { + debug_dnslib_ns("No zone found.\n"); + dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_NOTAUTH); + ns_axfr_send_and_clear(xfr); + return DNSLIB_ERROR; } - // Get pointer to the zone database +DEBUG_DNSLIB_NS( + char *name_str2 = dnslib_dname_to_str(zone->contents->apex->owner); + debug_dnslib_ns("Found zone for QNAME %s\n", name_str2); + free(name_str2); +); + xfr->zone = zone; + + return DNSLIB_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int dnslib_ns_xfr_send_error(dnslib_ns_xfr_t *xfr, dnslib_rcode_t rcode) +{ + dnslib_response2_set_rcode(xfr->response, rcode); + /*! \todo Probably rename the function. */ + return ns_axfr_send_and_clear(xfr); +} + +/*----------------------------------------------------------------------------*/ + +int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) +{ + if (xfr == NULL || nameserver == NULL || xfr->zone == NULL) { + return DNSLIB_EBADARG; + } + rcu_read_lock(); - dnslib_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); + + // take the contents and answer from them + dnslib_zone_contents_t *contents = dnslib_zone_get_contents(xfr->zone); - ret = ns_axfr(zonedb, xfr); + int ret = ns_axfr_from_zone(contents, xfr); /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL * and when it does not. E.g. if there was problem in sending @@ -2864,12 +2652,12 @@ int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) if (ret < 0) { debug_dnslib_ns("AXFR failed, sending SERVFAIL.\n"); // now only one type of error (SERVFAIL), later maybe more - size_t real_size; /*! \todo xfr->wire is not NULL, will fail on assert! */ dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->wire, - &real_size); - ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, real_size); + DNSLIB_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); + ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, + xfr->wire_size); } else if (ret > 0) { ret = DNSLIB_ERROR; } @@ -2885,95 +2673,35 @@ int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) int dnslib_ns_answer_ixfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) { - debug_dnslib_ns("ns_answer_ixfr()\n"); - - if (nameserver == NULL || xfr == NULL) { + if (nameserver == NULL || xfr == NULL || xfr->zone == NULL + || xfr->response == NULL) { return DNSLIB_EBADARG; } - - debug_dnslib_ns("ns_answer_ixfr(): implement me\n"); - - // initialize response packet structure - dnslib_packet_t *response = dnslib_packet_new( - DNSLIB_PACKET_PREALLOC_RESPONSE); - if (response == NULL) { - debug_dnslib_ns("Failed to create packet structure.\n"); - /*! \todo xfr->wire is not NULL, will fail on assert! */ - dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); - /*! \todo Hm, maybe send the packet? ;-) */ - return DNSLIB_EOK; - } - - int ret = dnslib_packet_set_max_size(response, xfr->wire_size); - - if (ret != DNSLIB_EOK) { - debug_dnslib_ns("Failed to init response structure.\n"); - /*! \todo xfr->wire is not NULL, will fail on assert! */ - dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); - /*! \todo Hm, maybe send the packet? ;-) */ - dnslib_packet_free(&response); - return DNSLIB_EOK; - } - - /*! \todo If TCP is used, more packets may be sent. - * If UDP is used, only one packet may be sent. - */ - - ret = dnslib_response2_init_from_query(response, xfr->query); - - if (ret != DNSLIB_EOK) { - debug_dnslib_ns("Failed to init response structure.\n"); - /*! \todo xfr->wire is not NULL, will fail on assert! */ - dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); - /*! \todo Hm, maybe send the packet? ;-) */ - dnslib_packet_free(&response); - return DNSLIB_EOK; - } - + // parse rest of the packet (we need the Authority record) - ret = dnslib_packet_parse_rest(xfr->query); + int ret = dnslib_packet_parse_rest(xfr->query); if (ret != DNSLIB_EOK) { debug_dnslib_ns("Failed to parse rest of the packet.\n"); /*! \todo Extract this to some function. */ - dnslib_response2_set_rcode(response, DNSLIB_RCODE_FORMERR); + dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_FORMERR); uint8_t *wire = NULL; size_t size = 0; - ret = dnslib_packet_to_wire(response, &wire, &size); + ret = dnslib_packet_to_wire(xfr->response, &wire, &size); if (ret != DNSLIB_EOK) { - dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_FORMERR, wire, &size); + dnslib_ns_error_response(nameserver, + xfr->query->header.id, + DNSLIB_RCODE_FORMERR, wire, + &size); } ret = xfr->send(xfr->session, &xfr->addr, wire, size); - dnslib_packet_free(&response); + dnslib_packet_free(&xfr->response); return ret; } - - xfr->response = response; - - // set the OPT RR to the response - if (dnslib_query_edns_supported(xfr->query)) { - ret = dnslib_response2_add_opt(xfr->response, - nameserver->opt_rr, 0); - if (ret != DNSLIB_EOK) { - debug_dnslib_ns("Failed to set OPT RR to the response" - ": %s\n", dnslib_strerror(ret)); - } - } - - // Get pointer to the zone database - rcu_read_lock(); - dnslib_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); - - ret = ns_ixfr(zonedb, xfr); + + ret = ns_ixfr(xfr); /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL * and when it does not. E.g. if there was problem in sending @@ -2984,13 +2712,15 @@ int dnslib_ns_answer_ixfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) // now only one type of error (SERVFAIL), later maybe more /*! \todo Extract this to some function. */ - dnslib_response2_set_rcode(response, DNSLIB_RCODE_SERVFAIL); + dnslib_response2_set_rcode(xfr->response, DNSLIB_RCODE_SERVFAIL); uint8_t *wire = NULL; size_t size = 0; - ret = dnslib_packet_to_wire(response, &wire, &size); + ret = dnslib_packet_to_wire(xfr->response, &wire, &size); if (ret != DNSLIB_EOK) { - dnslib_ns_error_response(nameserver, xfr->query->header.id, - DNSLIB_RCODE_SERVFAIL, wire, &size); + dnslib_ns_error_response(nameserver, + xfr->query->header.id, + DNSLIB_RCODE_SERVFAIL, wire, + &size); } ret = xfr->send(xfr->session, &xfr->addr, wire, size); @@ -2998,339 +2728,11 @@ int dnslib_ns_answer_ixfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) ret = DNSLIB_ERROR; } - rcu_read_unlock(); - dnslib_packet_free(&xfr->response); return ret; } -int dnslib_ns_process_response(dnslib_nameserver_t *nameserver, sockaddr_t *from, - dnslib_packet_t *packet, uint8_t *response_wire, - size_t *rsize) -{ - if (!packet || !rsize) { - return DNSLIB_EBADARG; - } - - /*! \todo Handle SOA query response, cancel EXPIRE timer - * and start AXFR transfer if needed. - * Reset REFRESH timer on finish. - */ - if (dnslib_packet_qtype(packet) == DNSLIB_RRTYPE_SOA) { - - /* No response. */ - *rsize = 0; - - /* Find matching zone and ID. */ - const dnslib_dname_t *zone_name = dnslib_packet_qname(packet); - dnslib_zone_t *zone = dnslib_zonedb_find_zone( - nameserver->zone_db, - zone_name); - if (!zone) { - return DNSLIB_ENOZONE; - } - if (!dnslib_zone_data(zone)) { - return DNSLIB_ENOZONE; - } - - /* Match ID against awaited. */ - zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); - uint16_t pkt_id = dnslib_packet_id(packet); - if ((int)pkt_id != zd->xfr_in.next_id) { - return DNSLIB_ERROR; - } - - /* Cancel EXPIRE timer. */ - evsched_t *sched = nameserver->server->sched; - event_t *expire_ev = zd->xfr_in.expire; - if (expire_ev) { - evsched_cancel(sched, expire_ev); - evsched_event_free(sched, expire_ev); - zd->xfr_in.expire = 0; - } - - /* Cancel REFRESH/RETRY timer. */ - event_t *refresh_ev = zd->xfr_in.timer; - if (refresh_ev) { - debug_dnslib_ns("zone: canceling REFRESH timer\n"); - evsched_cancel(sched, refresh_ev); - } - - /* Get zone contents. */ - rcu_read_lock(); - const dnslib_zone_contents_t *contents = - dnslib_zone_contents(zone); - - /* Check SOA SERIAL. */ - if (xfrin_transfer_needed(contents, packet) < 1) { - - /* Reinstall REFRESH timer. */ - uint32_t ref_tmr = 0; - - /* Retrieve SOA RDATA. */ - const dnslib_rrset_t *soa_rrs = 0; - const dnslib_rdata_t *soa_rr = 0; - soa_rrs = dnslib_node_rrset( - dnslib_zone_contents_apex(contents), - DNSLIB_RRTYPE_SOA); - soa_rr = dnslib_rrset_rdata(soa_rrs); - ref_tmr = dnslib_rdata_soa_refresh(soa_rr); - ref_tmr *= 1000; /* Convert to miliseconds. */ - - debug_dnslib_ns("zone: reinstalling REFRESH timer (%u ms)\n", - ref_tmr); - - evsched_schedule(sched, refresh_ev, ref_tmr); - rcu_read_unlock(); - return DNSLIB_EOK; - } - - /* Prepare XFR client transfer. */ - dnslib_ns_xfr_t xfr_req; - memset(&xfr_req, 0, sizeof(dnslib_ns_xfr_t)); - memcpy(&xfr_req.addr, from, sizeof(sockaddr_t)); - xfr_req.data = (void *)zone; - xfr_req.send = ns_send_cb; - - /* Select transfer method. */ - xfr_req.type = dnslib_ns_transfer_to_use(nameserver, contents); - - /* Unlock zone contents. */ - rcu_read_unlock(); - - /* Enqueue XFR request. */ - return xfr_request(nameserver->server->xfr_h, &xfr_req); - } - - - return DNSLIB_EOK; -} - -/*----------------------------------------------------------------------------*/ - -int dnslib_ns_process_notify(dnslib_nameserver_t *nameserver, sockaddr_t *from, - dnslib_packet_t *packet, uint8_t *response_wire, - size_t *rsize) -{ - if (!packet || !rsize) { - return DNSLIB_EBADARG; - } - - /* Assert no response size. */ - *rsize = 0; - - /* Find matching zone. */ - const dnslib_dname_t *zone_name = dnslib_packet_qname(packet); - dnslib_zone_t *zone = dnslib_zonedb_find_zone(nameserver->zone_db, - zone_name); - if (!zone) { - return DNSLIB_ENOZONE; - } - if (!dnslib_zone_data(zone)) { - return DNSLIB_ENOZONE; - } - - /* Match ID against awaited. */ - zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); - uint16_t pkt_id = dnslib_packet_id(packet); - notify_ev_t *ev = 0, *match = 0; - WALK_LIST(ev, zd->notify_pending) { - if ((int)pkt_id == ev->msgid) { - match = ev; - break; - } - } - - /* Found waiting NOTIFY query? */ - if (!match) { - debug_dnslib_ns("notify: no pending NOTIFY query found for ID=%u\n", - pkt_id); - return DNSLIB_ERROR; - } - - /* Cancel RETRY timer, NOTIFY is now finished. */ - evsched_t *sched = nameserver->server->sched; - if (match->timer) { - evsched_cancel(sched, match->timer); - evsched_event_free(sched, match->timer); - match->timer = 0; - rem_node(&match->n); - free(match); - } - - debug_dnslib_ns("notify: received response for pending NOTIFY query ID=%u\n", - pkt_id); - - return DNSLIB_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static int ns_find_zone_for_xfr(dnslib_ns_xfr_t *xfr, const char **zonefile, - const char **zonedb) -{ - // find the zone file name and zone db file name for the zone - conf_t *cnf = conf(); - node *n = NULL; - WALK_LIST(n, cnf->zones) { - conf_zone_t *zone_conf = (conf_zone_t *)n; - dnslib_dname_t *zone_name = dnslib_dname_new_from_str( - zone_conf->name, strlen(zone_conf->name), NULL); - if (zone_name == NULL) { - return DNSLIB_ENOMEM; - } - - int r = dnslib_dname_compare(zone_name, dnslib_node_owner( - dnslib_zone_contents_apex(xfr->zone))); - - /* Directly discard dname, won't be needed. */ - dnslib_dname_free(&zone_name); - - if (r == 0) { - // found the right zone - *zonefile = zone_conf->file; - *zonedb = zone_conf->db; - return DNSLIB_EOK; - } - } - - char *name = dnslib_dname_to_str(dnslib_node_owner( - dnslib_zone_contents_apex(xfr->zone))); - debug_dnslib_ns("No zone found for the zone received by transfer " - "(%s).\n", name); - free(name); - - return DNSLIB_ENOZONE; /*! \todo OK error code? */ -} - -/*----------------------------------------------------------------------------*/ - -static char *ns_find_free_filename(const char *old_name) -{ - // find zone name not present on the disk - int free_name = 0; - size_t name_size = strlen(old_name); - - char *new_name = malloc(name_size + 3); - if (new_name == NULL) { - return NULL; - } - memcpy(new_name, old_name, name_size); - new_name[name_size] = '.'; - new_name[name_size + 2] = 0; - - debug_dnslib_ns("Finding free name for the zone file.\n"); - int c = 48; - FILE *file; - while (!free_name && c < 58) { - new_name[name_size + 1] = c; - debug_dnslib_ns("Trying file name %s\n", new_name); - if ((file = fopen(new_name, "r")) != NULL) { - fclose(file); - ++c; - } else { - free_name = 1; - } - } - - if (free_name) { - return new_name; - } else { - free(new_name); - return NULL; - } -} - -/*----------------------------------------------------------------------------*/ - -static int ns_dump_xfr_zone_text(dnslib_ns_xfr_t *xfr, const char *zonefile) -{ - assert(xfr != NULL && xfr->zone != NULL && zonefile != NULL); - - char *new_zonefile = ns_find_free_filename(zonefile); - - if (new_zonefile == NULL) { - debug_dnslib_ns("Failed to find free filename for temporary " - "storage of the zone text file.\n"); - return DNSLIB_ERROR; /*! \todo New error code? */ - } - - int rc = zone_dump_text(xfr->zone, new_zonefile); - - if (rc != DNSLIB_EOK) { - debug_dnslib_ns("Failed to save the zone to text zone file %s." - "\n", new_zonefile); - free(new_zonefile); - return DNSLIB_ERROR; - } - - // if successful, replace the old file with the new one - // TODO - - free(new_zonefile); - return DNSLIB_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static int ns_dump_xfr_zone_binary(dnslib_ns_xfr_t *xfr, const char *zonedb, - const char *zonefile) -{ - assert(xfr != NULL && xfr->zone != NULL && zonedb != NULL); - - char *new_zonedb = ns_find_free_filename(zonedb); - - if (new_zonedb == NULL) { - debug_dnslib_ns("Failed to find free filename for temporary " - "storage of the zone binary file.\n"); - return DNSLIB_ERROR; /*! \todo New error code? */ - } - - int rc = dnslib_zdump_binary(xfr->zone, new_zonedb, 0, zonefile); - - if (rc != DNSLIB_EOK) { - debug_dnslib_ns("Failed to save the zone to binary zone db %s." - "\n", new_zonedb); - free(new_zonedb); - return DNSLIB_ERROR; - } - - // if successful, replace the old file with the new one - // TODO - - free(new_zonedb); - return DNSLIB_EOK; -} - -/*----------------------------------------------------------------------------*/ - -static int ns_save_zone(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) -{ - assert(nameserver != NULL && xfr != NULL && xfr->zone != NULL - && dnslib_zone_contents_apex(xfr->zone) != NULL); - - const char *zonefile = NULL; - const char *zonedb = NULL; - - int ret = ns_find_zone_for_xfr(xfr, &zonefile, &zonedb); - if (ret != DNSLIB_EOK) { - return ret; - } - - assert(zonefile != NULL && zonedb != NULL); - - // dump the zone into text zone file - ret = ns_dump_xfr_zone_text(xfr, zonefile); - if (ret != DNSLIB_EOK) { - return ret; - } - // dump the zone into binary db file - ret = ns_dump_xfr_zone_binary(xfr, zonedb, zonefile); - - return ret; -} - /*----------------------------------------------------------------------------*/ int dnslib_ns_process_axfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) @@ -3344,7 +2746,7 @@ int dnslib_ns_process_axfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *x debug_dnslib_ns("ns_process_axfrin: incoming packet\n"); int ret = xfrin_process_axfr_packet(xfr->wire, xfr->wire_size, - (dnslib_zone_contents_t **)(&xfr->data)); + (dnslib_zone_contents_t **)(&xfr->data)); if (ret > 0) { // transfer finished debug_dnslib_ns("ns_process_axfrin: AXFR finished, zone created.\n"); @@ -3352,40 +2754,36 @@ int dnslib_ns_process_axfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *x * Adjust zone so that node count is set properly and nodes are * marked authoritative / delegation point. */ - xfr->zone = (dnslib_zone_contents_t *)xfr->data; + dnslib_zone_contents_t *zone = + (dnslib_zone_contents_t *)xfr->data; debug_dnslib_ns("ns_process_axfrin: adjusting zone.\n"); - dnslib_zone_contents_adjust_dnames(xfr->zone); + dnslib_zone_contents_adjust_dnames(zone); /* Create and fill hash table */ debug_dnslib_ns("ns_process_axfrin: filling hash table.\n"); - int rc = dnslib_zone_contents_create_and_fill_hash_table( - xfr->zone); + int rc = dnslib_zone_contents_create_and_fill_hash_table(zone); if (rc != DNSLIB_EOK) { return DNSLIB_ERROR; // TODO: change error code } - dnslib_zone_contents_dump(xfr->zone, 0); - debug_dnslib_ns("AXFR finished. Saving to zone file.\n"); - - // save the zone to the disk - rc = ns_save_zone(nameserver, xfr); - if (rc != DNSLIB_EOK) { - debug_dnslib_ns("Freeing created zone: %p.\n", xfr->zone); - dnslib_zone_contents_deep_free(&xfr->zone); - debug_dnslib_ns("%p.\n", xfr->zone); - return rc; - } - return DNSLIB_EOK; - } else { - return ret; + dnslib_zone_contents_dump(zone, 0); } + + return ret; } /*----------------------------------------------------------------------------*/ -int dnslib_ns_switch_zone(dnslib_nameserver_t *nameserver, dnslib_zone_contents_t *zone) +int dnslib_ns_switch_zone(dnslib_nameserver_t *nameserver, + dnslib_ns_xfr_t *xfr) { + if (xfr == NULL || nameserver == NULL || xfr->data == NULL) { + return DNSLIB_EBADARG; + } + + dnslib_zone_contents_t *zone = (dnslib_zone_contents_t *)xfr->data; + debug_dnslib_ns("Replacing zone by new one: %p\n", zone); // find the zone in the zone db @@ -3509,15 +2907,6 @@ int dnslib_ns_process_ixfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *x /*----------------------------------------------------------------------------*/ -dnslib_ns_xfr_type_t dnslib_ns_transfer_to_use(dnslib_nameserver_t *nameserver, - const dnslib_zone_contents_t *zone) -{ - /*! \todo Implement. */ - return NS_XFR_TYPE_AIN; -} - -/*----------------------------------------------------------------------------*/ - void dnslib_ns_destroy(dnslib_nameserver_t **nameserver) { synchronize_rcu(); @@ -3533,28 +2922,3 @@ void dnslib_ns_destroy(dnslib_nameserver_t **nameserver) free(*nameserver); *nameserver = NULL; } - -/*----------------------------------------------------------------------------*/ - -int dnslib_ns_conf_hook(const struct conf_t *conf, void *data) -{ - dnslib_nameserver_t *ns = (dnslib_nameserver_t *)data; - debug_dnslib_ns("Event: reconfiguring name server.\n"); - - dnslib_zonedb_t *old_db = 0; - - int ret = zones_update_db_from_config(conf, ns, &old_db); - if (ret != DNSLIB_EOK) { - return ret; - } - // Wait until all readers finish with reading the zones. - synchronize_rcu(); - - debug_dnslib_ns("Nameserver's zone db: %p, old db: %p\n", ns->zone_db, old_db); - - // Delete all deprecated zones and delete the old database. - dnslib_zonedb_deep_free(&old_db); - - return DNSLIB_EOK; -} - diff --git a/src/knot/server/name-server.h b/src/knot/server/name-server.h index 5589cb9f2..e8c79f568 100644 --- a/src/knot/server/name-server.h +++ b/src/knot/server/name-server.h @@ -49,6 +49,8 @@ typedef struct dnslib_nameserver { uint8_t *err_response; /*!< Prepared generic error response. */ size_t err_resp_size; /*!< Size of the prepared error response. */ dnslib_opt_rr_t *opt_rr; /*!< OPT RR with the server's EDNS0 info. */ + + /*! \todo REMOVE */ struct server_t *server; /*!< Pointer to server. */ } dnslib_nameserver_t; @@ -67,17 +69,9 @@ typedef struct dnslib_ns_xfr { uint8_t *wire; size_t wire_size; void *data; - dnslib_zone_contents_t *zone; + dnslib_zone_t *zone; } dnslib_ns_xfr_t; -/*! \todo Document me. */ -typedef enum dnslib_ns_xfr_type_t { - NS_XFR_TYPE_AIN, /*!< AXFR-IN request (start transfer). */ - NS_XFR_TYPE_AOUT, /*!< AXFR-OUT request (incoming transfer). */ - NS_XFR_TYPE_IIN, /*!< IXFR-IN request (start transfer). */ - NS_XFR_TYPE_IOUT /*!< IXFR-OUT request (incoming transfer). */ -} dnslib_ns_xfr_type_t; - /*----------------------------------------------------------------------------*/ /*! * \brief Allocates and initializes the name server structure. @@ -188,8 +182,13 @@ int dnslib_ns_answer_normal(dnslib_nameserver_t *nameserver, dnslib_packet_t *qu * \retval KNOT_EACCES sender is not authorized to request NOTIFY. * \retval KNOT_EMALF if an error occured and the response is not valid. */ -int dnslib_ns_answer_notify(dnslib_nameserver_t *nameserver, dnslib_packet_t *query, - sockaddr_t *from, uint8_t *response_wire, size_t *rsize); +//int dnslib_ns_answer_notify(dnslib_nameserver_t *nameserver, +// dnslib_packet_t *query, uint8_t *response_wire, +// size_t *rsize, const dnslib_zone_t **zone); + +int dnslib_ns_init_xfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr); + +int dnslib_ns_xfr_send_error(dnslib_ns_xfr_t *xfr, dnslib_rcode_t rcode); /*! * \brief Processes an AXFR query. @@ -224,41 +223,15 @@ int dnslib_ns_answer_axfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr) */ int dnslib_ns_answer_ixfr(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr); -/*! - * \brief Processes normal response packet. - * - * \param nameserver Name server structure to provide the needed data. - * \param from Address of the response sender. - * \param packet Parsed response packet. - * \param response_wire Place for the response in wire format. - * \param rsize Input: maximum acceptable size of the response. Output: real - * size of the response. - * - * \retval KNOT_EOK if a valid response was created. - * \retval KNOT_EINVAL on invalid parameters or packet. - * \retval KNOT_EMALF if an error occured and the response is not valid. - */ -int dnslib_ns_process_response(dnslib_nameserver_t *nameserver, sockaddr_t *from, - dnslib_packet_t *packet, uint8_t *response_wire, - size_t *rsize); -/*! - * \brief Processes NOTIFY response packet. - * - * \param nameserver Name server structure to provide the needed data. - * \param from Address of the response sender. - * \param packet Parsed response packet. - * \param response_wire Place for the response in wire format. - * \param rsize Input: maximum acceptable size of the response. Output: real - * size of the response. - * - * \retval KNOT_EOK if a valid response was created. - * \retval KNOT_EINVAL on invalid parameters or packet. - * \retval KNOT_EMALF if an error occured and the response is not valid. - */ -int dnslib_ns_process_notify(dnslib_nameserver_t *nameserver, sockaddr_t *from, - dnslib_packet_t *packet, uint8_t *response_wire, - size_t *rsize); +//int dnslib_ns_process_response(dnslib_nameserver_t *nameserver, sockaddr_t *from, +// dnslib_packet_t *packet, uint8_t *response_wire, +// size_t *rsize); + + +//int dnslib_ns_process_notify(dnslib_nameserver_t *nameserver, sockaddr_t *from, +// dnslib_packet_t *packet, uint8_t *response_wire, +// size_t *rsize); /*! * \brief Processes an AXFR-IN packet. @@ -268,9 +241,11 @@ int dnslib_ns_process_notify(dnslib_nameserver_t *nameserver, sockaddr_t *from, * * \todo Document me. */ -int dnslib_ns_process_axfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr); +int dnslib_ns_process_axfrin(dnslib_nameserver_t *nameserver, + dnslib_ns_xfr_t *xfr); -int dnslib_ns_switch_zone(dnslib_nameserver_t *nameserver, dnslib_zone_contents_t *zone); +int dnslib_ns_switch_zone(dnslib_nameserver_t *nameserver, + dnslib_ns_xfr_t *xfr); /*! * \brief Processes an IXFR-IN packet. @@ -280,7 +255,8 @@ int dnslib_ns_switch_zone(dnslib_nameserver_t *nameserver, dnslib_zone_contents_ * * \todo Document me. */ -int dnslib_ns_process_ixfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *xfr); +int dnslib_ns_process_ixfrin(dnslib_nameserver_t *nameserver, + dnslib_ns_xfr_t *xfr); /*! * \brief Decides what type of transfer should be used to update the given zone. @@ -290,8 +266,8 @@ int dnslib_ns_process_ixfrin(dnslib_nameserver_t *nameserver, dnslib_ns_xfr_t *x * * \retval */ -dnslib_ns_xfr_type_t dnslib_ns_transfer_to_use(dnslib_nameserver_t *nameserver, - const dnslib_zone_contents_t *zone); +/*xfr_type_t dnslib_ns_transfer_to_use(dnslib_nameserver_t *nameserver, + const dnslib_zone_contents_t *zone);*/ /*! * \brief Properly destroys the name server structure. @@ -312,7 +288,7 @@ void dnslib_ns_destroy(dnslib_nameserver_t **nameserver); * \retval KNOT_EINVAL * \retval KNOT_ERROR */ -int dnslib_ns_conf_hook(const struct conf_t *conf, void *data); +//int dnslib_ns_conf_hook(const struct conf_t *conf, void *data); #endif /* _KNOT_NAME_SERVER_H_ */ diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c index febc91144..55ba30615 100644 --- a/src/knot/server/notify.c +++ b/src/knot/server/notify.c @@ -12,6 +12,11 @@ #include "dnslib/zonedb.h" #include "dnslib/dnslib-common.h" #include "dnslib/error.h" +#include "knot/server/zones.h" +#include "common/acl.h" +#include "common/evsched.h" +#include "knot/other/debug.h" +#include "knot/server/server.h" /*----------------------------------------------------------------------------*/ /* Non-API functions */ @@ -143,23 +148,71 @@ int notify_create_request(const dnslib_zone_contents_t *zone, uint8_t *buffer, /*----------------------------------------------------------------------------*/ -int notify_process_request(dnslib_packet_t *notify, - dnslib_zonedb_t *zonedb, - const dnslib_zone_contents_t **zone, +static int notify_check_and_schedule(const dnslib_nameserver_t *nameserver, + const dnslib_zone_t *zone, + sockaddr_t *from) +{ + if (zone == NULL || from == NULL || dnslib_zone_data(zone) == NULL) { + return KNOT_EINVAL; + } + + /* Check ACL for notify-in. */ + zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); + if (from) { + if (acl_match(zd->notify_in, from) == ACL_DENY) { + /* rfc1996: Ignore request and report incident. */ + char straddr[SOCKADDR_STRLEN]; + sockaddr_tostr(from, straddr, sizeof(straddr)); + debug_notify("Unauthorized NOTIFY request " + "from %s:%d.\n", + straddr, sockaddr_portnum(from)); + return DNSLIB_ERROR; + } else { + debug_notify("notify: authorized NOTIFY query.\n"); + } + } + + /*! \todo Packet may contain updated RRs. */ + + /* Cancel EXPIRE timer. */ + evsched_t *sched = nameserver->server->sched; + event_t *expire_ev = zd->xfr_in.expire; + if (expire_ev) { + debug_notify("notify: canceling EXPIRE timer\n"); + evsched_cancel(sched, expire_ev); + evsched_event_free(sched, expire_ev); + zd->xfr_in.expire = 0; + } + + /* Cancel REFRESH/RETRY timer. */ + event_t *refresh_ev = zd->xfr_in.timer; + if (refresh_ev) { + debug_notify("notify: canceling REFRESH timer for XFRIN\n"); + evsched_cancel(sched, refresh_ev); + + /* Set REFRESH timer for now. */ + evsched_schedule(sched, refresh_ev, 0); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int notify_process_request(const dnslib_nameserver_t *nameserver, + dnslib_packet_t *notify, + sockaddr_t *from, uint8_t *buffer, size_t *size) { /*! \todo Most of this function is identical to xfrin_transfer_needed() * - it will be fine to merge the code somehow. */ - if (notify == NULL || zone == NULL || buffer == NULL || size == NULL) { + if (notify == NULL || nameserver == NULL || buffer == NULL + || size == NULL || from == NULL) { return KNOT_EINVAL; } - *zone = NULL; - - //debug_ns("Notify request - parsed: %zu, total wire size: %zu\n", - // notify->parsed, notify->size); int ret; if (notify->parsed < notify->size) { @@ -177,31 +230,74 @@ int notify_process_request(dnslib_packet_t *notify, // find the zone const dnslib_dname_t *qname = dnslib_packet_qname(notify); - const dnslib_zone_t *z = dnslib_zonedb_find_zone_for_name(zonedb, qname); + const dnslib_zone_t *z = dnslib_zonedb_find_zone_for_name( + nameserver->zone_db, qname); if (z == NULL) { return KNOT_ERROR; /*! \todo Some other error. */ } - *zone = dnslib_zone_contents(z); - if (*zone == NULL) { - return KNOT_ERROR; /*! \todo Some other error. */ - } - - /*! \todo Merge this with ns_answer_notify(). - * According to RFC 1996, slave should - * behave as if the REFRESH timer has expired - * i.e. it should send SOA query to the master. - * No further processing after this comment is needed. - */ - + notify_check_and_schedule(nameserver, z, from); + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -int notify_process_response(const dnslib_zone_contents_t *zone, - dnslib_packet_t *notify) +int notify_process_response(const dnslib_nameserver_t *nameserver, + dnslib_packet_t *notify, + sockaddr_t *from, + uint8_t *buffer, size_t *size) { - return KNOT_ENOTSUP; + if (nameserver == NULL || notify == NULL || from == NULL + || buffer == NULL || size == NULL) { + return KNOT_EINVAL; + } + + /* Assert no response size. */ + *size = 0; + + /* Find matching zone. */ + const dnslib_dname_t *zone_name = dnslib_packet_qname(notify); + dnslib_zone_t *zone = dnslib_zonedb_find_zone(nameserver->zone_db, + zone_name); + if (!zone) { + return KNOT_ENOENT; + } + if (!dnslib_zone_data(zone)) { + return KNOT_ENOENT; + } + + /* Match ID against awaited. */ + zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); + uint16_t pkt_id = dnslib_packet_id(notify); + notify_ev_t *ev = 0, *match = 0; + WALK_LIST(ev, zd->notify_pending) { + if ((int)pkt_id == ev->msgid) { + match = ev; + break; + } + } + + /* Found waiting NOTIFY query? */ + if (!match) { + debug_notify("notify: no pending NOTIFY query found for ID=%u\n", + pkt_id); + return KNOT_ERROR; + } + + /* Cancel RETRY timer, NOTIFY is now finished. */ + evsched_t *sched = nameserver->server->sched; + if (match->timer) { + evsched_cancel(sched, match->timer); + evsched_event_free(sched, match->timer); + match->timer = 0; + rem_node(&match->n); + free(match); + } + + debug_notify("notify: received response for pending NOTIFY query ID=%u\n", + pkt_id); + + return KNOT_EOK; } diff --git a/src/knot/server/notify.h b/src/knot/server/notify.h index 9b005264a..fd5b55dbc 100644 --- a/src/knot/server/notify.h +++ b/src/knot/server/notify.h @@ -20,6 +20,7 @@ #include "dnslib/zonedb.h" #include "common/lists.h" #include "common/sockaddr.h" +#include "knot/server/name-server.h" /*! * \brief Pending NOTIFY event. @@ -50,6 +51,20 @@ typedef struct notify_ev_t { int notify_create_request(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size); +/*! + * \brief Processes normal response packet. + * + * \param nameserver Name server structure to provide the needed data. + * \param from Address of the response sender. + * \param packet Parsed response packet. + * \param response_wire Place for the response in wire format. + * \param rsize Input: maximum acceptable size of the response. Output: real + * size of the response. + * + * \retval KNOT_EOK if a valid response was created. + * \retval KNOT_EINVAL on invalid parameters or packet. + * \retval KNOT_EMALF if an error occured and the response is not valid. + */ /*! * \brief Evaluates incoming NOTIFY request and produces a reply. * @@ -66,13 +81,29 @@ int notify_create_request(const dnslib_zone_contents_t *zone, uint8_t *buffer, * \retval KNOT_EMALF * \retval KNOT_ERROR */ -int notify_process_request(dnslib_packet_t *notify, - dnslib_zonedb_t *zonedb, - const dnslib_zone_contents_t **zone, +int notify_process_request(const dnslib_nameserver_t *nameserver, + dnslib_packet_t *notify, + sockaddr_t *from, uint8_t *buffer, size_t *size); -int notify_process_response(const dnslib_zone_contents_t *zone, - dnslib_packet_t *notify); +/*! + * \brief Processes NOTIFY response packet. + * + * \param nameserver Name server structure to provide the needed data. + * \param from Address of the response sender. + * \param packet Parsed response packet. + * \param response_wire Place for the response in wire format. + * \param rsize Input: maximum acceptable size of the response. Output: real + * size of the response. + * + * \retval KNOT_EOK if a valid response was created. + * \retval KNOT_EINVAL on invalid parameters or packet. + * \retval KNOT_EMALF if an error occured and the response is not valid. + */ +int notify_process_response(const dnslib_nameserver_t *nameserver, + dnslib_packet_t *notify, + sockaddr_t *from, + uint8_t *buffer, size_t *size); #endif /* _KNOT_NOTIFY_H_ */ diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 45bffe7d8..6855e238d 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -20,6 +20,7 @@ #include "knot/other/error.h" #include "knot/stat/stat.h" #include "dnslib/wire.h" +#include "knot/server/zones.h" /*! \brief TCP watcher. */ typedef struct tcp_io_t { @@ -160,7 +161,7 @@ static void tcp_handle(struct ev_loop *loop, ev_io *w, int revents) break; case DNSLIB_QUERY_AXFR: memset(&xfr, 0, sizeof(dnslib_ns_xfr_t)); - xfr.type = NS_XFR_TYPE_AOUT; + xfr.type = XFR_TYPE_AOUT; xfr.query = packet; xfr.send = xfr_send_cb; xfr.session = w->fd; @@ -170,7 +171,7 @@ static void tcp_handle(struct ev_loop *loop, ev_io *w, int revents) return; case DNSLIB_QUERY_IXFR: memset(&xfr, 0, sizeof(dnslib_ns_xfr_t)); - xfr.type = NS_XFR_TYPE_IOUT; + xfr.type = XFR_TYPE_IOUT; xfr.query = packet; /* Will be freed after processing. */ xfr.send = xfr_send_cb; xfr.session = w->fd; diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index 6e252cf65..093a4dc1f 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -19,6 +19,8 @@ #include "dnslib/wire.h" #include "dnslib/consts.h" #include "dnslib/packet.h" +#include "knot/server/zones.h" +#include "knot/server/notify.h" int udp_master(dthread_t *thread) { @@ -141,27 +143,36 @@ int udp_master(dthread_t *thread) /* Response types. */ case DNSLIB_RESPONSE_NORMAL: - res = dnslib_ns_process_response(ns, &addr, packet, - qbuf, &resp_len); + res = zones_process_response(ns, &addr, packet, + qbuf, &resp_len); +// res = dnslib_ns_process_response(); break; case DNSLIB_RESPONSE_AXFR: case DNSLIB_RESPONSE_IXFR: case DNSLIB_RESPONSE_NOTIFY: - res = dnslib_ns_process_notify(ns, &addr, packet, - qbuf, &resp_len); + res = notify_process_response(ns, packet, &addr, + qbuf, &resp_len); break; /* Query types. */ case DNSLIB_QUERY_NORMAL: - res = dnslib_ns_answer_normal(ns, packet, qbuf, &resp_len); + res = dnslib_ns_answer_normal(ns, packet, qbuf, + &resp_len); break; case DNSLIB_QUERY_AXFR: case DNSLIB_QUERY_IXFR: /*! \todo Send error, not available on UDP. */ break; case DNSLIB_QUERY_NOTIFY: - res = dnslib_ns_answer_notify(ns, packet, &addr, - qbuf, &resp_len); + rcu_read_lock(); +// const dnslib_zone_t *zone = NULL; +// res = dnslib_ns_answer_notify(ns, packet, qbuf, +// &resp_len, &zone); + res = notify_process_request(ns, packet, &addr, + qbuf, &resp_len); +// if (res == DNSLIB_EOK) { +// res = zones_notify_schedule(zone, &addr); +// } break; case DNSLIB_QUERY_UPDATE: /*! \todo Implement query notify/update. */ diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index ba0073931..18382d3b8 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -19,6 +19,8 @@ #include "knot/server/socket.h" #include "knot/server/tcp-handler.h" #include "knot/server/xfr-in.h" +#include "knot/server/zones.h" +#include "dnslib/error.h" /*! \brief XFR event wrapper for libev. */ struct xfr_io_t @@ -73,10 +75,10 @@ static inline void xfr_client_ev(struct ev_loop *loop, ev_io *w, int revents) /* Process incoming packet. */ switch(request->type) { - case NS_XFR_TYPE_AIN: + case XFR_TYPE_AIN: ret = dnslib_ns_process_axfrin(xfr_w->h->ns, request); break; - case NS_XFR_TYPE_IIN: + case XFR_TYPE_IIN: ret = dnslib_ns_process_ixfrin(xfr_w->h->ns, request); break; default: @@ -85,15 +87,37 @@ static inline void xfr_client_ev(struct ev_loop *loop, ev_io *w, int revents) } /* Check return code for errors. */ - if (ret != KNOT_EOK) { + if (ret < 0) { + /*! \todo Log error. */ return; } /* Check finished zone. */ - if (request->zone) { + if (ret > 0) { + switch(request->type) { + case XFR_TYPE_AIN: + ret = zones_save_zone(request); + if (ret != KNOT_EOK) { + /*! \todo Log error. */ + return; + } + ret = dnslib_ns_switch_zone(xfr_w->h->ns, request); + if (ret != KNOT_EOK) { + /*! \todo Log error. */ + return; + } + break; + case XFR_TYPE_IIN: + /*! \todo save changesets */ + /*! \todo udpate zone?? */ + break; + default: + ret = KNOT_EINVAL; + break; + } /* Save finished zone and reload. */ - xfrin_zone_transferred(xfr_w->h->ns, request->zone); +// xfrin_zone_transferred(xfr_w->h->ns, request->zone); /* Return error code to make TCP client disconnect. */ ev_io_stop(loop, (ev_io *)w); @@ -166,10 +190,10 @@ static inline void xfr_bridge_ev(struct ev_loop *loop, ev_io *w, int revents) ret = KNOT_ERROR; size_t bufsize = req->wire_size; switch(req->type) { - case NS_XFR_TYPE_AIN: + case XFR_TYPE_AIN: ret = xfrin_create_axfr_query(contents, req->wire, &bufsize); break; - case NS_XFR_TYPE_IIN: + case XFR_TYPE_IIN: ret = xfrin_create_ixfr_query(contents, req->wire, &bufsize); break; default: @@ -369,18 +393,53 @@ int xfr_master(dthread_t *thread) /* Handle request. */ const char *req_type = ""; + dnslib_rcode_t rcode; + + rcu_read_lock(); + switch(xfr.type) { - case NS_XFR_TYPE_AOUT: + case XFR_TYPE_AOUT: req_type = "axfr-out"; + + ret = dnslib_ns_init_xfr(xfrh->ns, &xfr); + if (ret != DNSLIB_EOK) { + debug_xfr("xfr_master: failed to init XFR: %s\n", + dnslib_strerror(ret)); + socket_close(xfr.session); + } + + ret = zones_xfr_check_zone(&xfr, &rcode); + if (ret != KNOT_EOK) { + dnslib_ns_xfr_send_error(&xfr, rcode); + socket_close(xfr.session); + } + ret = dnslib_ns_answer_axfr(xfrh->ns, &xfr); dnslib_packet_free(&xfr.query); /* Free query. */ debug_xfr("xfr_master: ns_answer_axfr() = %d.\n", ret); if (ret != KNOT_EOK) { socket_close(xfr.session); } + + rcu_read_unlock(); break; - case NS_XFR_TYPE_IOUT: + case XFR_TYPE_IOUT: req_type = "ixfr-out"; + + ret = dnslib_ns_init_xfr(xfrh->ns, &xfr); + if (ret != DNSLIB_EOK) { + debug_xfr("xfr_master: failed to init XFR: %s\n", + dnslib_strerror(ret)); + socket_close(xfr.session); + } + + ret = zones_xfr_check_zone(&xfr, &rcode); + if (ret != KNOT_EOK) { + dnslib_ns_xfr_send_error(&xfr, rcode); + socket_close(xfr.session); + } + + /*! \todo Init XFR, check zone, answer. */ ret = dnslib_ns_answer_ixfr(xfrh->ns, &xfr); dnslib_packet_free(&xfr.query); /* Free query. */ debug_xfr("xfr_master: ns_answer_ixfr() = %d.\n", ret); @@ -388,12 +447,12 @@ int xfr_master(dthread_t *thread) socket_close(xfr.session); } break; - case NS_XFR_TYPE_AIN: + case XFR_TYPE_AIN: req_type = "axfr-in"; evqueue_write(xfrh->cq, &xfr, sizeof(dnslib_ns_xfr_t)); ret = KNOT_EOK; break; - case NS_XFR_TYPE_IIN: + case XFR_TYPE_IIN: req_type = "ixfr-in"; evqueue_write(xfrh->cq, &xfr, sizeof(dnslib_ns_xfr_t)); ret = KNOT_EOK; diff --git a/src/knot/server/xfr-in.c b/src/knot/server/xfr-in.c index 2ea1a3f9d..2299b3550 100644 --- a/src/knot/server/xfr-in.c +++ b/src/knot/server/xfr-in.c @@ -259,13 +259,13 @@ int xfrin_create_ixfr_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, /*----------------------------------------------------------------------------*/ -int xfrin_zone_transferred(dnslib_nameserver_t *nameserver, - dnslib_zone_contents_t *zone) -{ - debug_xfr("Switching zone in nameserver.\n"); - return dnslib_ns_switch_zone(nameserver, zone); - //return KNOT_ENOTSUP; -} +//int xfrin_zone_transferred(dnslib_nameserver_t *nameserver, +// dnslib_zone_contents_t *zone) +//{ +// debug_xfr("Switching zone in nameserver.\n"); +// return dnslib_ns_switch_zone(nameserver, zone); +// //return KNOT_ENOTSUP; +//} /*----------------------------------------------------------------------------*/ diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 8c360c3a4..65b348079 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -16,6 +16,9 @@ #include "knot/server/server.h" #include "knot/server/xfr-in.h" #include "knot/server/zones.h" +#include "dnslib/error.h" +#include "dnslib/zone-dump.h" +#include "knot/server/name-server.h" /*----------------------------------------------------------------------------*/ @@ -958,3 +961,356 @@ int zones_zonefile_sync(dnslib_zone_t *zone) return KNOT_EOK; } + +/*----------------------------------------------------------------------------*/ + +int zones_xfr_check_zone(dnslib_ns_xfr_t *xfr, dnslib_rcode_t *rcode) +{ + if (xfr == NULL || xfr->zone == NULL || rcode == NULL) { + *rcode = DNSLIB_RCODE_SERVFAIL; + return KNOT_EINVAL; + } + + /* Check zone data. */ + zonedata_t *zd = (zonedata_t *)xfr->zone->data; + if (zd == NULL) { + debug_zones("Invalid zone data.\n"); + *rcode = DNSLIB_RCODE_SERVFAIL; + return KNOT_ERROR; + } + + // Check xfr-out ACL + if (acl_match(zd->xfr_out, &xfr->addr) == ACL_DENY) { + debug_zones("Request for AXFR OUT is not authorized.\n"); + *rcode = DNSLIB_RCODE_REFUSED; + return KNOT_ERROR; + } else { + debug_zones("Authorized AXFR OUT request.\n"); + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +/*! + * \brief Wrapper for TCP send. + * \todo Implement generic fd pool properly with callbacks. + */ +#include "knot/server/tcp-handler.h" +static int zones_send_cb(int fd, sockaddr_t *addr, uint8_t *msg, size_t msglen) +{ + return tcp_send(fd, msg, msglen); +} + +/*----------------------------------------------------------------------------*/ + +int zones_process_response(dnslib_nameserver_t *nameserver, + sockaddr_t *from, + dnslib_packet_t *packet, uint8_t *response_wire, + size_t *rsize) +{ + if (!packet || !rsize || nameserver == NULL || from == NULL || + response_wire == NULL) { + return KNOT_EINVAL; + } + + /*! \todo Handle SOA query response, cancel EXPIRE timer + * and start AXFR transfer if needed. + * Reset REFRESH timer on finish. + */ + if (dnslib_packet_qtype(packet) == DNSLIB_RRTYPE_SOA) { + + /* No response. */ + *rsize = 0; + + /* Find matching zone and ID. */ + const dnslib_dname_t *zone_name = dnslib_packet_qname(packet); + /*! \todo Change the access to the zone db. */ + dnslib_zone_t *zone = dnslib_zonedb_find_zone( + nameserver->zone_db, + zone_name); + if (!zone) { + return KNOT_EINVAL; + } + if (!dnslib_zone_data(zone)) { + return KNOT_EINVAL; + } + + /* Match ID against awaited. */ + zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); + uint16_t pkt_id = dnslib_packet_id(packet); + if ((int)pkt_id != zd->xfr_in.next_id) { + return KNOT_ERROR; + } + + /* Cancel EXPIRE timer. */ + evsched_t *sched = nameserver->server->sched; + event_t *expire_ev = zd->xfr_in.expire; + if (expire_ev) { + evsched_cancel(sched, expire_ev); + evsched_event_free(sched, expire_ev); + zd->xfr_in.expire = 0; + } + + /* Cancel REFRESH/RETRY timer. */ + event_t *refresh_ev = zd->xfr_in.timer; + if (refresh_ev) { + debug_zones("zone: canceling REFRESH timer\n"); + evsched_cancel(sched, refresh_ev); + } + + /* Get zone contents. */ + rcu_read_lock(); + const dnslib_zone_contents_t *contents = + dnslib_zone_contents(zone); + + /* Check SOA SERIAL. */ + if (xfrin_transfer_needed(contents, packet) < 1) { + + /* Reinstall REFRESH timer. */ + uint32_t ref_tmr = 0; + + /* Retrieve SOA RDATA. */ + const dnslib_rrset_t *soa_rrs = 0; + const dnslib_rdata_t *soa_rr = 0; + soa_rrs = dnslib_node_rrset( + dnslib_zone_contents_apex(contents), + DNSLIB_RRTYPE_SOA); + soa_rr = dnslib_rrset_rdata(soa_rrs); + ref_tmr = dnslib_rdata_soa_refresh(soa_rr); + ref_tmr *= 1000; /* Convert to miliseconds. */ + + debug_zones("zone: reinstalling REFRESH timer (%u ms)\n", + ref_tmr); + + evsched_schedule(sched, refresh_ev, ref_tmr); + rcu_read_unlock(); + return KNOT_EOK; + } + + /* Prepare XFR client transfer. */ + dnslib_ns_xfr_t xfr_req; + memset(&xfr_req, 0, sizeof(dnslib_ns_xfr_t)); + memcpy(&xfr_req.addr, from, sizeof(sockaddr_t)); + xfr_req.data = (void *)zone; + xfr_req.send = zones_send_cb; + + /* Select transfer method. */ + xfr_req.type = zones_transfer_to_use(contents); + + /* Unlock zone contents. */ + rcu_read_unlock(); + + /* Enqueue XFR request. */ + return xfr_request(nameserver->server->xfr_h, &xfr_req); + } + + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +xfr_type_t zones_transfer_to_use(const dnslib_zone_contents_t *zone) +{ + /*! \todo Implement. */ + return XFR_TYPE_AIN; +} + +/*----------------------------------------------------------------------------*/ + +static int zones_find_zone_for_xfr(const dnslib_zone_contents_t *zone, + const char **zonefile, const char **zonedb) +{ + // find the zone file name and zone db file name for the zone + conf_t *cnf = conf(); + node *n = NULL; + WALK_LIST(n, cnf->zones) { + conf_zone_t *zone_conf = (conf_zone_t *)n; + dnslib_dname_t *zone_name = dnslib_dname_new_from_str( + zone_conf->name, strlen(zone_conf->name), NULL); + if (zone_name == NULL) { + return KNOT_ENOMEM; + } + + int r = dnslib_dname_compare(zone_name, dnslib_node_owner( + dnslib_zone_contents_apex(zone))); + + /* Directly discard dname, won't be needed. */ + dnslib_dname_free(&zone_name); + + if (r == 0) { + // found the right zone + *zonefile = zone_conf->file; + *zonedb = zone_conf->db; + return KNOT_EOK; + } + } + + char *name = dnslib_dname_to_str(dnslib_node_owner( + dnslib_zone_contents_apex(zone))); + debug_zones("No zone found for the zone received by transfer " + "(%s).\n", name); + free(name); + + return KNOT_ENOENT; +} + +/*----------------------------------------------------------------------------*/ + +static char *zones_find_free_filename(const char *old_name) +{ + // find zone name not present on the disk + int free_name = 0; + size_t name_size = strlen(old_name); + + char *new_name = malloc(name_size + 3); + if (new_name == NULL) { + return NULL; + } + memcpy(new_name, old_name, name_size); + new_name[name_size] = '.'; + new_name[name_size + 2] = 0; + + debug_dnslib_ns("Finding free name for the zone file.\n"); + int c = 48; + FILE *file; + while (!free_name && c < 58) { + new_name[name_size + 1] = c; + debug_dnslib_ns("Trying file name %s\n", new_name); + if ((file = fopen(new_name, "r")) != NULL) { + fclose(file); + ++c; + } else { + free_name = 1; + } + } + + if (free_name) { + return new_name; + } else { + free(new_name); + return NULL; + } +} + +/*----------------------------------------------------------------------------*/ + +static int zones_dump_xfr_zone_text(dnslib_zone_contents_t *zone, + const char *zonefile) +{ + assert(zone != NULL && zonefile != NULL); + + char *new_zonefile = zones_find_free_filename(zonefile); + + if (new_zonefile == NULL) { + debug_zones("Failed to find free filename for temporary " + "storage of the zone text file.\n"); + return KNOT_ERROR; /*! \todo New error code? */ + } + + int rc = zone_dump_text(zone, new_zonefile); + + if (rc != KNOT_EOK) { + debug_zones("Failed to save the zone to text zone file %s." + "\n", new_zonefile); + free(new_zonefile); + return KNOT_ERROR; + } + + /*! \todo if successful, replace the old file with the new one */ + + free(new_zonefile); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +static int ns_dump_xfr_zone_binary(dnslib_zone_contents_t *zone, + const char *zonedb, + const char *zonefile) +{ + assert(zone != NULL && zonedb != NULL); + + char *new_zonedb = zones_find_free_filename(zonedb); + + if (new_zonedb == NULL) { + debug_zones("Failed to find free filename for temporary " + "storage of the zone binary file.\n"); + return KNOT_ERROR; /*! \todo New error code? */ + } + + int rc = dnslib_zdump_binary(zone, new_zonedb, 0, zonefile); + + if (rc != DNSLIB_EOK) { + debug_zones("Failed to save the zone to binary zone db %s." + "\n", new_zonedb); + free(new_zonedb); + return KNOT_ERROR; + } + + /*! \todo if successful, replace the old file with the new one */ + + free(new_zonedb); + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_save_zone(const dnslib_ns_xfr_t *xfr) +{ + if (xfr == NULL || xfr->data == NULL) { + return KNOT_EINVAL; + } + + dnslib_zone_contents_t *zone = + (dnslib_zone_contents_t *)xfr->data; + + const char *zonefile = NULL; + const char *zonedb = NULL; + + int ret = zones_find_zone_for_xfr(zone, &zonefile, &zonedb); + if (ret != KNOT_EOK) { + return ret; + } + + assert(zonefile != NULL && zonedb != NULL); + + // dump the zone into text zone file + ret = zones_dump_xfr_zone_text(zone, zonefile); + if (ret != KNOT_EOK) { + return KNOT_ERROR; + } + // dump the zone into binary db file + ret = ns_dump_xfr_zone_binary(zone, zonedb, zonefile); + if (ret != KNOT_EOK) { + return KNOT_ERROR; + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int zones_ns_conf_hook(const struct conf_t *conf, void *data) +{ + dnslib_nameserver_t *ns = (dnslib_nameserver_t *)data; + debug_zones("Event: reconfiguring name server.\n"); + + dnslib_zonedb_t *old_db = 0; + + int ret = zones_update_db_from_config(conf, ns, &old_db); + if (ret != KNOT_EOK) { + return ret; + } + // Wait until all readers finish with reading the zones. + synchronize_rcu(); + + debug_zones("Nameserver's zone db: %p, old db: %p\n", ns->zone_db, + old_db); + + // Delete all deprecated zones and delete the old database. + dnslib_zonedb_deep_free(&old_db); + + return KNOT_EOK; +} diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index f7436e312..defd29574 100644 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -56,6 +56,14 @@ typedef struct zonedata_t uint32_t zonefile_serial; } zonedata_t; +/*! \todo Document me. */ +typedef enum xfr_type_t { + XFR_TYPE_AIN, /*!< AXFR-IN request (start transfer). */ + XFR_TYPE_AOUT, /*!< AXFR-OUT request (incoming transfer). */ + XFR_TYPE_IIN, /*!< IXFR-IN request (start transfer). */ + XFR_TYPE_IOUT /*!< IXFR-OUT request (incoming transfer). */ +} xfr_type_t; + /*! * \brief Update zone database according to configuration. * @@ -97,6 +105,31 @@ int zones_update_db_from_config(const conf_t *conf, dnslib_nameserver_t *ns, */ int zones_zonefile_sync(dnslib_zone_t *zone); +int zones_xfr_check_zone(dnslib_ns_xfr_t *xfr, dnslib_rcode_t *rcode); + +int zones_process_response(dnslib_nameserver_t *nameserver, + sockaddr_t *from, + dnslib_packet_t *packet, uint8_t *response_wire, + size_t *rsize); + +xfr_type_t zones_transfer_to_use(const dnslib_zone_contents_t *zone); + +int zones_save_zone(const dnslib_ns_xfr_t *xfr); + +/*! + * \brief Name server config hook. + * + * Routine for dynamic name server reconfiguration. + * + * \param conf Current configuration. + * \param data Instance of the nameserver structure to update. + * + * \retval KNOT_EOK on success. + * \retval KNOT_EINVAL + * \retval KNOT_ERROR + */ +int zones_ns_conf_hook(const struct conf_t *conf, void *data); + #endif // _KNOT_ZONES_H_ /*! @} */ -- GitLab