diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c index 8ebe9b508f47b0948280d477d9d8cc4e9149abcc..a28f2ad5ef485dc5f6ebf8f79936366b6ab635b4 100644 --- a/src/knot/ctl/remote.c +++ b/src/knot/ctl/remote.c @@ -668,7 +668,7 @@ int remote_process(server_t *s, conf_iface_t *ctl_if, int sock, tsig_name = pkt->tsig_rr->owner; } acl_match_t *match = acl_find(conf()->ctl.acl, &ss, tsig_name); - knot_rcode_t ts_rc = 0; + uint16_t ts_rc = 0; uint16_t ts_trc = 0; uint64_t ts_tmsigned = 0; if (match == NULL) { diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c index d9125c77d77f16221927b36e498998038a6be38c..3878d773a7f9e13312b9747cdb381a6a2279ce54 100644 --- a/src/knot/nameserver/axfr.c +++ b/src/knot/nameserver/axfr.c @@ -224,7 +224,7 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata) } } -int axfr_process_answer(knot_ns_xfr_t *xfr) +int axfr_process_answer(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) { /* * Here we assume that 'xfr' contains TSIG information @@ -234,7 +234,7 @@ int axfr_process_answer(knot_ns_xfr_t *xfr) dbg_ns("ns_process_axfrin: incoming packet, wire size: %zu\n", xfr->wire_size); - int ret = xfrin_process_axfr_packet(xfr, + int ret = xfrin_process_axfr_packet(pkt, xfr, (knot_zone_contents_t **)&xfr->data); if (ret > 0) { // transfer finished dbg_ns("ns_process_axfrin: AXFR finished, zone created.\n"); diff --git a/src/knot/nameserver/axfr.h b/src/knot/nameserver/axfr.h index 99d701a4c14bf68af6e8cf30e48ec1e22b8fa6f9..8bfb95a827798819213171791e30b37c3372f3e0 100644 --- a/src/knot/nameserver/axfr.h +++ b/src/knot/nameserver/axfr.h @@ -62,10 +62,11 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata); /*! * \brief Processes an AXFR query response. * + * \param pkt Processed packet. * \param xfr Persistent transfer-specific data. * */ -int axfr_process_answer(knot_ns_xfr_t *xfr); +int axfr_process_answer(knot_pkt_t *pkt, knot_ns_xfr_t *xfr); #endif /* _KNOT_AXFR_H_ */ diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c index f55188d35875aa5c6a2473c6ff88a69148b0aabf..83ffa1d9db42b53b55b26e33afc156d2da8ebc34 100644 --- a/src/knot/nameserver/ixfr.c +++ b/src/knot/nameserver/ixfr.c @@ -338,7 +338,7 @@ int ixfr_answer(knot_pkt_t *pkt, struct query_data *qdata) return ret; } -int ixfr_process_answer(knot_ns_xfr_t *xfr) +int ixfr_process_answer(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) { dbg_ns("ns_process_ixfrin: incoming packet\n"); @@ -347,7 +347,7 @@ int ixfr_process_answer(knot_ns_xfr_t *xfr) * and the digest of the query sent to the master or the previous * digest. */ - int ret = xfrin_process_ixfr_packet(xfr); + int ret = xfrin_process_ixfr_packet(pkt, xfr); if (ret == XFRIN_RES_FALLBACK) { dbg_ns("ns_process_ixfrin: Fallback to AXFR.\n"); diff --git a/src/knot/nameserver/ixfr.h b/src/knot/nameserver/ixfr.h index 23b072d10292bdc397943fb98cc4a55199db4142..c8a680714a777d45012026b46d64bf29a675a041 100644 --- a/src/knot/nameserver/ixfr.h +++ b/src/knot/nameserver/ixfr.h @@ -45,6 +45,7 @@ int ixfr_answer(knot_pkt_t *pkt, struct query_data *qdata); /*! * \brief Process an IXFR query response. * + * \param pkt Processed packet. * \param xfr Persistent transfer-specific data. * * \retval KNOT_EOK If this packet was processed successfuly and another packet @@ -64,7 +65,7 @@ int ixfr_answer(knot_pkt_t *pkt, struct query_data *qdata); * \retval Other If any other error occured. The connection should be closed. * */ -int ixfr_process_answer(knot_ns_xfr_t *xfr); +int ixfr_process_answer(knot_pkt_t *pkt, knot_ns_xfr_t *xfr); #endif /* _KNOT_IXFR_H_ */ diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c index 7e79a6af71c9c91c8ab0a2f965bb8cb8894ee38d..ac3b18c134a18ac0e9d378b1d4a371d77436af8f 100644 --- a/src/knot/nameserver/update.c +++ b/src/knot/nameserver/update.c @@ -11,9 +11,7 @@ #include "libknot/tsig-op.h" /* Forward decls. */ -static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, - knot_rcode_t *rcode, const struct sockaddr_storage *addr, - knot_tsig_key_t *tsig_key); +static int zones_process_update_auth(struct query_data *qdata); /* AXFR-specific logging (internal, expects 'qdata' variable set). */ #define UPDATE_LOG(severity, msg...) \ @@ -93,14 +91,12 @@ static int update_prereq_check(struct query_data *qdata) * \note Permissions section means probably policies and fine grained * access control, not transaction security. */ - knot_rcode_t rcode = KNOT_RCODE_NOERROR; knot_ddns_prereq_t *prereqs = NULL; - int ret = knot_ddns_process_prereqs(query, &prereqs, &rcode); + int ret = knot_ddns_process_prereqs(query, &prereqs, &qdata->rcode); if (ret == KNOT_EOK) { - ret = knot_ddns_check_prereqs(contents, &prereqs, &rcode); + ret = knot_ddns_check_prereqs(contents, &prereqs, &qdata->rcode); knot_ddns_prereqs_free(&prereqs); } - qdata->rcode = rcode; return ret; } @@ -114,13 +110,7 @@ static int update_process(knot_pkt_t *resp, struct query_data *qdata) } /*! \todo Reusing the API for compatibility reasons. */ - knot_rcode_t rcode = qdata->rcode; - ret = zones_process_update_auth((zone_t *)qdata->zone, qdata->query, - &rcode, - qdata->param->query_source, - qdata->sign.tsig_key); - qdata->rcode = rcode; - return ret; + return zones_process_update_auth(qdata); } int update_answer(knot_pkt_t *pkt, struct query_data *qdata) @@ -189,11 +179,11 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata) * NOTE: Mostly copied from xfrin_apply_changesets(). Should be refactored in * order to get rid of duplicate code. */ -int knot_ns_process_update(const knot_pkt_t *query, - knot_zone_contents_t *old_contents, - knot_zone_contents_t **new_contents, - knot_changesets_t *chgs, knot_rcode_t *rcode, - uint32_t new_serial) +static int knot_ns_process_update(const knot_pkt_t *query, + knot_zone_contents_t *old_contents, + knot_zone_contents_t **new_contents, + knot_changesets_t *chgs, uint16_t *rcode, + uint32_t new_serial) { if (query == NULL || old_contents == NULL || chgs == NULL || EMPTY_LIST(chgs->sets) || new_contents == NULL || rcode == NULL) { @@ -268,14 +258,15 @@ static int replan_zone_sign_after_ddns(zone_t *zone, uint32_t refresh_at) * \retval KNOT_EOK if successful. * \retval error if not. */ -static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, - knot_rcode_t *rcode, const struct sockaddr_storage *addr, - knot_tsig_key_t *tsig_key) +static int zones_process_update_auth(struct query_data *qdata) { - assert(zone); - assert(query); - assert(rcode); - assert(addr); + assert(qdata); + assert(qdata->zone); + + zone_t *zone = (zone_t *)qdata->zone; + conf_zone_t *zone_config = zone->conf; + knot_tsig_key_t *tsig_key = qdata->sign.tsig_key; + const struct sockaddr_storage *addr = qdata->param->query_source; int ret = KNOT_EOK; @@ -286,7 +277,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, } char *r_str = xfr_remote_str(addr, keytag); char *msg = sprintf_alloc("UPDATE of '%s' from %s", - zone->conf->name, r_str ? r_str : "'unknown'"); + zone_config->name, r_str ? r_str : "'unknown'"); free(r_str); free(keytag); @@ -296,7 +287,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, */ knot_changesets_t *chgsets = knot_changesets_create(); if (chgsets == NULL) { - *rcode = KNOT_RCODE_SERVFAIL; + qdata->rcode = KNOT_RCODE_SERVFAIL; log_zone_error("%s Cannot create changesets structure.\n", msg); free(msg); return ret; @@ -308,18 +299,18 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, free(msg); return KNOT_ENOMEM; } - *rcode = KNOT_RCODE_SERVFAIL; /* SERVFAIL unless it applies correctly. */ + qdata->rcode = KNOT_RCODE_SERVFAIL; /* SERVFAIL unless it applies correctly. */ uint32_t new_serial = zones_next_serial(zone); knot_zone_contents_t *new_contents = NULL; knot_zone_contents_t *old_contents = zone->contents; - ret = knot_ns_process_update(query, old_contents, &new_contents, - chgsets, rcode, new_serial); + ret = knot_ns_process_update(qdata->query, old_contents, &new_contents, + chgsets, &qdata->rcode, new_serial); if (ret != KNOT_EOK) { if (ret > 0) { log_zone_notice("%s: No change to zone made.\n", msg); - *rcode = KNOT_RCODE_NOERROR; + qdata->rcode = KNOT_RCODE_NOERROR; } knot_changesets_free(&chgsets); @@ -331,12 +322,11 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, knot_changeset_t *sec_ch = NULL; uint32_t refresh_at = 0; - assert(zone->conf); - if (zone->conf->dnssec_enable) { + if (zone_config->dnssec_enable) { sec_chs = knot_changesets_create(); sec_ch = knot_changesets_create_changeset(sec_chs); if (sec_chs == NULL || sec_ch == NULL) { - xfrin_rollback_update(zone->contents, &new_contents, + xfrin_rollback_update(old_contents, &new_contents, chgsets->changes); knot_changesets_free(&chgsets); free(msg); @@ -346,7 +336,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, // Apply changeset to zone created by DDNS processing - if (zone->conf->dnssec_enable) { + if (zone_config->dnssec_enable) { /*! * Check if the UPDATE changed DNSKEYs. If yes, resign the whole * zone, if not, sign only the changeset. @@ -354,13 +344,13 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, */ if (zones_dnskey_changed(old_contents, new_contents) || zones_nsec3param_changed(old_contents, new_contents)) { - ret = knot_dnssec_zone_sign(new_contents, zone->conf, + ret = knot_dnssec_zone_sign(new_contents, zone_config, sec_ch, KNOT_SOA_SERIAL_KEEP, &refresh_at, new_serial); } else { // Sign the created changeset - ret = knot_dnssec_sign_changeset(new_contents, zone->conf, + ret = knot_dnssec_sign_changeset(new_contents, zone_config, knot_changesets_get_last(chgsets), sec_ch, KNOT_SOA_SERIAL_KEEP, &refresh_at, @@ -370,7 +360,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, if (ret != KNOT_EOK) { log_zone_error("%s: Failed to sign incoming update (%s)" "\n", msg, knot_strerror(ret)); - xfrin_rollback_update(zone->contents, &new_contents, + xfrin_rollback_update(old_contents, &new_contents, chgsets->changes); knot_changesets_free(&chgsets); knot_changesets_free(&sec_chs); @@ -386,7 +376,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, if (ret != KNOT_EOK) { log_zone_error("%s: Failed to save new entry to journal (%s)\n", msg, knot_strerror(ret)); - xfrin_rollback_update(zone->contents, &new_contents, + xfrin_rollback_update(old_contents, &new_contents, chgsets->changes); zones_free_merged_changesets(chgsets, sec_chs); free(msg); @@ -409,7 +399,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, } // Plan zone resign if needed - assert(zone->dnssec.timer); + assert(qdata->zone->dnssec.timer); ret = replan_zone_sign_after_ddns(zone, refresh_at); if (ret != KNOT_EOK) { log_zone_error("%s: Failed to replan zone sign (%s)\n", @@ -424,7 +414,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, if (ret != KNOT_EOK) { zones_store_changesets_rollback(transaction); zones_free_merged_changesets(chgsets, sec_chs); - xfrin_rollback_update(zone->contents, &new_contents, + xfrin_rollback_update(old_contents, &new_contents, chgsets->changes); free(msg); return ret; @@ -437,7 +427,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, if (ret != KNOT_EOK) { log_zone_error("%s: Failed to commit new journal entry " "(%s).\n", msg, knot_strerror(ret)); - xfrin_rollback_update(zone->contents, &new_contents, + xfrin_rollback_update(old_contents, &new_contents, chgsets->changes); zones_free_merged_changesets(chgsets, sec_chs); free(msg); @@ -450,16 +440,17 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, rcu_read_unlock(); /* Unlock for switch. */ ret = xfrin_switch_zone(zone, new_contents, XFR_TYPE_UPDATE); rcu_read_lock(); /* Relock */ - zone_release(zone); /* Release held pointer. */ if (ret != KNOT_EOK) { log_zone_error("%s: Failed to replace current zone (%s)\n", msg, knot_strerror(ret)); // Cleanup old and new contents - xfrin_rollback_update(zone->contents, &new_contents, + xfrin_rollback_update(old_contents, &new_contents, chgsets->changes); /* Free changesets, but not the data. */ zones_free_merged_changesets(chgsets, sec_chs); + zone_release(zone); + qdata->zone = NULL; return KNOT_ERROR; } @@ -472,7 +463,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, // Free changesets, but not the data. zones_free_merged_changesets(chgsets, sec_chs); assert(ret == KNOT_EOK); - *rcode = KNOT_RCODE_NOERROR; /* Mark as successful. */ + qdata->rcode = KNOT_RCODE_NOERROR; /* Mark as successful. */ if (new_signatures) { log_zone_info("%s: Successfuly signed.\n", msg); } @@ -484,10 +475,16 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, mem_trim(); /* Sync zonefile immediately if configured. */ - if (zone->conf->dbsync_timeout == 0) { + if (zone_config->dbsync_timeout == 0) { zones_schedule_zonefile_sync(zone, 0); } + /* Since we unlocked RCU read lock, it is possible that the + * zone was modified/removed in the background. Therefore, + * we must NOT touch the zone after we release it here. */ + zone_release(zone); + qdata->zone = NULL; + return ret; } diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index a3f1b9353548c73cf83963b12f69fe86419c6bb3..701d933cfdab5ee49079c2604c606d5648d66fcb 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -109,31 +109,6 @@ static int xfr_recv_tcp(int fd, struct sockaddr *addr, uint8_t *buf, size_t bufl static int xfr_recv_udp(int fd, struct sockaddr *addr, uint8_t *buf, size_t buflen) { return recv(fd, buf, buflen, 0); } -/*! \todo This should be obsoleted by the generic response parsing layer. */ -static int parse_packet(knot_pkt_t *packet, knot_pkt_type_t *type) -{ - dbg_xfr("%s(%p, %p)\n", __func__, packet, type); - if (packet == NULL || type == NULL) { - return KNOT_EINVAL; - } - - // 1) create empty response - int ret = KNOT_ERROR; - *type = KNOT_QUERY_INVALID; - if ((ret = knot_pkt_parse_question(packet)) != KNOT_EOK) { - dbg_xfr("%s: couldn't parse question = %d\n", __func__, ret); - return KNOT_RCODE_FORMERR; - } - - // 2) determine the query type - *type = knot_pkt_type(packet); - if (*type == KNOT_QUERY_INVALID) { - return KNOT_RCODE_NOTIMPL; - } - - return KNOT_RCODE_NOERROR; -} - /*! \brief Create forwarded query. */ static int forward_packet(knot_ns_xfr_t *data, knot_pkt_t *pkt) { @@ -203,11 +178,7 @@ static int xfr_task_setmsg(knot_ns_xfr_t *rq, const char *keytag) } /* Prepare log message. */ - const char *zname = rq->zname; - if (zname == NULL) { - zname = rq->zone->conf->name; - } - + const char *zname = rq->zone->conf->name; rq->msg = sprintf_alloc(xd->name, zname, kstr ? kstr : "'unknown'"); free(kstr); return KNOT_EOK; @@ -289,7 +260,6 @@ static void xfr_task_cleanup(knot_ns_xfr_t *rq) /* Cleanup other data - so that the structure may be reused. */ rq->packet_nr = 0; rq->tsig_data_size = 0; - hattrie_clear(rq->lookup_tree); } /*! \brief End task properly and free it. */ @@ -545,7 +515,6 @@ static int xfr_async_finish(fdset_t *set, unsigned id) switch(rq->type) { case XFR_TYPE_AIN: case XFR_TYPE_IIN: - rq->lookup_tree = hattrie_create(); if (ret != KNOT_EOK) { pthread_mutex_lock(&zone->lock); zone->xfr_in.state = XFR_IDLE; @@ -654,62 +623,52 @@ static int xfr_task_finalize(knot_ns_xfr_t *rq) } /*! \brief Query response event handler function. */ -static int xfr_task_resp(xfrhandler_t *xfr, knot_ns_xfr_t *rq) +static int xfr_task_resp(xfrhandler_t *xfr, knot_ns_xfr_t *rq, knot_pkt_t *pkt) { - knot_pkt_t *re = knot_pkt_new(rq->wire, rq->wire_size, NULL); - if (re == NULL) { - return KNOT_ENOMEM; - } - - knot_pkt_type_t rt = KNOT_RESPONSE_NORMAL; - int ret = parse_packet(re, &rt); - if (ret != KNOT_EOK) { - knot_pkt_free(&re); - return KNOT_EOK; /* Ignore */ - } + knot_pkt_type_t pkt_type = knot_pkt_type(pkt); /* Ignore other packets. */ - switch(rt) { + switch(pkt_type) { case KNOT_RESPONSE_NORMAL: case KNOT_RESPONSE_NOTIFY: case KNOT_RESPONSE_UPDATE: break; default: - knot_pkt_free(&re); + knot_pkt_free(&pkt); return KNOT_EOK; /* Ignore */ } - ret = knot_pkt_parse_payload(re, KNOT_PF_NO_MERGE); + int ret = knot_pkt_parse_payload(pkt, KNOT_PF_NO_MERGE); if (ret != KNOT_EOK) { - knot_pkt_free(&re); + knot_pkt_free(&pkt); return KNOT_EOK; /* Ignore */ } /* Check TSIG. */ - const knot_rrset_t * tsig_rr = re->tsig_rr; + const knot_rrset_t * tsig_rr = pkt->tsig_rr; if (rq->tsig_key != NULL) { - ret = knot_tsig_client_check(tsig_rr, re->wire, re->size, + ret = knot_tsig_client_check(tsig_rr, pkt->wire, pkt->size, rq->digest, rq->digest_size, rq->tsig_key, 0); if (ret != KNOT_EOK) { log_zone_error("%s %s\n", rq->msg, knot_strerror(ret)); - knot_pkt_free(&re); + knot_pkt_free(&pkt); return KNOT_ECONNREFUSED; } } /* Process response. */ - switch(rt) { + switch(pkt_type) { case KNOT_RESPONSE_NORMAL: ret = zones_process_response(xfr->server, rq->packet_nr, &rq->addr, - re); + pkt); break; case KNOT_RESPONSE_NOTIFY: - ret = notify_process_response(re, rq->packet_nr); + ret = notify_process_response(pkt, rq->packet_nr); break; case KNOT_RESPONSE_UPDATE: - ret = forward_packet_response(rq, re); + ret = forward_packet_response(rq, pkt); if (ret == KNOT_EOK) { log_zone_info("%s Forwarded response.\n", rq->msg); } @@ -719,7 +678,6 @@ static int xfr_task_resp(xfrhandler_t *xfr, knot_ns_xfr_t *rq) break; } - knot_pkt_free(&re); if (ret == KNOT_EUPTODATE) { /* Check up-to-date zone. */ log_zone_info("%s %s (serial %u)\n", rq->msg, knot_strerror(ret), @@ -769,16 +727,44 @@ static int xfr_fallback_axfr(knot_ns_xfr_t *rq) return xfr_task_start(rq); } -static int xfr_task_xfer(xfrhandler_t *xfr, knot_ns_xfr_t *rq) +static int xfr_parse_packet(knot_pkt_t *pkt) +{ + /* This is important, don't merge RRs together. The SOAs are ordered + * in a special way for a reason. */ + int ret = knot_pkt_parse(pkt, KNOT_PF_NO_MERGE); + if (ret != KNOT_EOK) { + return ret; + } + + // check if the response is OK + if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) { + return KNOT_EXFRREFUSED; + } + + // check if the TC bit is set (it must not be) + if (knot_wire_get_tc(pkt->wire)) { + return KNOT_EMALF; + } + + return ret; +} + +static int xfr_task_xfer(xfrhandler_t *xfr, knot_ns_xfr_t *rq, knot_pkt_t *pkt) { + /* Parse transfer packet. */ + int ret = xfr_parse_packet(pkt); + if (ret != KNOT_EOK) { + log_zone_error("%s %s\n", rq->msg, knot_strerror(ret)); + return ret; + } + /* Process incoming packet. */ - int ret = KNOT_EOK; switch(rq->type) { case XFR_TYPE_AIN: - ret = axfr_process_answer(rq); + ret = axfr_process_answer(pkt, rq); break; case XFR_TYPE_IIN: - ret = ixfr_process_answer(rq); + ret = ixfr_process_answer(pkt, rq); break; default: ret = KNOT_EINVAL; @@ -792,7 +778,7 @@ static int xfr_task_xfer(xfrhandler_t *xfr, knot_ns_xfr_t *rq) xfr_task_cleanup(rq); rq->type = XFR_TYPE_AIN; rq->msg[XFR_MSG_DLTTR] = 'A'; - ret = axfr_process_answer(rq); + ret = axfr_process_answer(pkt, rq); } /* IXFR refused, try again with AXFR. */ @@ -876,15 +862,32 @@ static int xfr_process_event(xfrhandler_t *xfr, knot_ns_xfr_t *rq) rq->wire_size = n; } - /* Handle SOA/NOTIFY responses. */ + /* Parse question. */ + knot_pkt_t *pkt = knot_pkt_new(rq->wire, rq->wire_size, NULL); + if (pkt == NULL) { + return KNOT_ENOMEM; + } + + int ret = knot_pkt_parse_question(pkt); + if (ret != KNOT_EOK) { + knot_pkt_free(&pkt); + return ret; + } + + /* Process packet by request type. */ switch(rq->type) { case XFR_TYPE_NOTIFY: case XFR_TYPE_SOA: case XFR_TYPE_FORWARD: - return xfr_task_resp(xfr, rq); + ret = xfr_task_resp(xfr, rq, pkt); + break; default: - return xfr_task_xfer(xfr, rq); + ret = xfr_task_xfer(xfr, rq, pkt); + break; } + + knot_pkt_free(&pkt); + return ret; } /*! \brief Sweep inactive connection. */ @@ -1183,10 +1186,6 @@ int xfr_task_free(knot_ns_xfr_t *rq) return KNOT_EINVAL; } - /* Free DNAME trie. */ - hattrie_free(rq->lookup_tree); - rq->lookup_tree = NULL; - /* Free TSIG buffers. */ free(rq->digest); rq->digest = NULL; diff --git a/src/knot/server/xfr-handler.h b/src/knot/server/xfr-handler.h index e79241535cb1775aacfdde77540edb05a6c35cc7..c08358358dd41abb97a76c926fd0dae392710be6 100644 --- a/src/knot/server/xfr-handler.h +++ b/src/knot/server/xfr-handler.h @@ -99,7 +99,6 @@ typedef struct knot_ns_xfr { struct sockaddr_storage addr, saddr; knot_pkt_t *query; knot_pkt_t *response; - knot_rcode_t rcode; xfr_callback_t send; xfr_callback_t recv; int session; @@ -119,7 +118,6 @@ typedef struct knot_ns_xfr { size_t wire_maxlen; void *data; zone_t *zone; - char* zname; knot_zone_contents_t *new_contents; char *msg; @@ -142,7 +140,6 @@ typedef struct knot_ns_xfr { int fwd_src_fd; /*!< Query originator fd. */ struct sockaddr_storage fwd_addr; - uint16_t tsig_rcode; uint64_t tsig_prev_time_signed; /*! @@ -152,8 +149,6 @@ typedef struct knot_ns_xfr { * number counted from last TSIG check. */ int packet_nr; - - hattrie_t *lookup_tree; } knot_ns_xfr_t; /*! diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 70aaab305671dc7f3fb1c8f5dfb862b2a810a0ea..b663ee20f4d47b54a9b706fa6a7c01cec4d697dd 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -798,7 +798,7 @@ static int zones_serial_policy(const zone_t *zone) return zone->conf->serial_policy; } -uint32_t zones_next_serial(zone_t *zone) +uint32_t zones_next_serial(const zone_t *zone) { assert(zone); @@ -1746,7 +1746,7 @@ void zones_schedule_zonefile_sync(zone_t *zone, uint32_t timeout) int zones_verify_tsig_query(const knot_pkt_t *query, const knot_tsig_key_t *key, - knot_rcode_t *rcode, uint16_t *tsig_rcode, + uint16_t *rcode, uint16_t *tsig_rcode, uint64_t *tsig_prev_time_signed) { assert(key != NULL); diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index 60de09a47c4ed9cbb72631f38b6555b35fb3a491..c1a1321b386d56add54815be3e24a85353eda4e4 100644 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -233,7 +233,7 @@ void zones_schedule_zonefile_sync(zone_t *zone, uint32_t timeout); */ int zones_verify_tsig_query(const knot_pkt_t *query, const knot_tsig_key_t *key, - knot_rcode_t *rcode, uint16_t *tsig_rcode, + uint16_t *rcode, uint16_t *tsig_rcode, uint64_t *tsig_prev_time_signed); /*! @@ -284,7 +284,7 @@ int zones_merge_and_store_changesets(zone_t *zone, journal_t **transaction); void zones_free_merged_changesets(knot_changesets_t *diff_chs, knot_changesets_t *sec_chs); -uint32_t zones_next_serial(zone_t *zone); +uint32_t zones_next_serial(const zone_t *zone); #endif // _KNOTD_ZONES_H_ diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c index bbcb4ce0ea5ad5c8cee98cd8122ad7057b3fefb1..85f56427741d43933532174cc9f6958ce8f95c73 100644 --- a/src/knot/updates/ddns.c +++ b/src/knot/updates/ddns.c @@ -202,7 +202,7 @@ static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs, /*----------------------------------------------------------------------------*/ static int knot_ddns_check_exist(const knot_zone_contents_t *zone, - const knot_rrset_t *rrset, knot_rcode_t *rcode) + const knot_rrset_t *rrset, uint16_t *rcode) { assert(zone != NULL); assert(rrset != NULL); @@ -233,7 +233,7 @@ static int knot_ddns_check_exist(const knot_zone_contents_t *zone, static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, const knot_rrset_t *rrset, - knot_rcode_t *rcode) + uint16_t *rcode) { assert(zone != NULL); assert(rrset != NULL); @@ -275,7 +275,7 @@ static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, const knot_rrset_t *rrset, - knot_rcode_t *rcode) + uint16_t *rcode) { assert(zone != NULL); assert(rrset != NULL); @@ -308,7 +308,7 @@ static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, const knot_dname_t *dname, - knot_rcode_t *rcode) + uint16_t *rcode) { assert(zone != NULL); assert(dname != NULL); @@ -338,7 +338,7 @@ static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, const knot_dname_t *dname, - knot_rcode_t *rcode) + uint16_t *rcode) { assert(zone != NULL); assert(dname != NULL); @@ -368,7 +368,7 @@ static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ int knot_ddns_check_zone(const knot_zone_contents_t *zone, - const knot_pkt_t *query, knot_rcode_t *rcode) + const knot_pkt_t *query, uint16_t *rcode) { if (zone == NULL || query == NULL || rcode == NULL) { if (rcode != NULL) { @@ -395,7 +395,7 @@ int knot_ddns_check_zone(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ int knot_ddns_process_prereqs(const knot_pkt_t *query, - knot_ddns_prereq_t **prereqs, knot_rcode_t *rcode) + knot_ddns_prereq_t **prereqs, uint16_t *rcode) { if (query == NULL || prereqs == NULL || rcode == NULL) { return KNOT_EINVAL; @@ -433,7 +433,7 @@ int knot_ddns_process_prereqs(const knot_pkt_t *query, /*----------------------------------------------------------------------------*/ int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, - knot_ddns_prereq_t **prereqs, knot_rcode_t *rcode) + knot_ddns_prereq_t **prereqs, uint16_t *rcode) { int i, ret; @@ -491,7 +491,7 @@ int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, static int knot_ddns_check_update(const knot_rrset_t *rrset, const knot_pkt_t *query, - knot_rcode_t *rcode) + uint16_t *rcode) { /* Accept both subdomain and dname match. */ dbg_ddns("Checking UPDATE packet.\n"); @@ -1636,7 +1636,7 @@ int knot_ddns_process_update(knot_zone_contents_t *zone, const knot_pkt_t *query, knot_changeset_t *changeset, knot_changes_t *changes, - knot_rcode_t *rcode, uint32_t new_serial) + uint16_t *rcode, uint32_t new_serial) { if (zone == NULL || query == NULL || changeset == NULL || rcode == NULL || changes == NULL) { diff --git a/src/knot/updates/ddns.h b/src/knot/updates/ddns.h index da3645006fc5b98296d6929b645df964d1be01b6..f6993b65bf3a3a1ec47462bd7a6205083a99aaf8 100644 --- a/src/knot/updates/ddns.h +++ b/src/knot/updates/ddns.h @@ -58,19 +58,19 @@ typedef struct knot_ddns_prereq_t { } knot_ddns_prereq_t; int knot_ddns_check_zone(const knot_zone_contents_t *zone, - const knot_pkt_t *query, knot_rcode_t *rcode); + const knot_pkt_t *query, uint16_t *rcode); int knot_ddns_process_prereqs(const knot_pkt_t *query, - knot_ddns_prereq_t **prereqs, knot_rcode_t *rcode); + knot_ddns_prereq_t **prereqs, uint16_t *rcode); int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, - knot_ddns_prereq_t **prereqs, knot_rcode_t *rcode); + knot_ddns_prereq_t **prereqs, uint16_t *rcode); int knot_ddns_process_update(knot_zone_contents_t *zone, const knot_pkt_t *query, knot_changeset_t *changeset, knot_changes_t *changes, - knot_rcode_t *rcode, uint32_t new_serial); + uint16_t *rcode, uint32_t new_serial); void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq); diff --git a/src/knot/updates/xfr-in.c b/src/knot/updates/xfr-in.c index 584a77c75bbe6676b8c446f9d7db681523a18e14..f862934685e100084e2a0a74d098e386e164beb1 100644 --- a/src/knot/updates/xfr-in.c +++ b/src/knot/updates/xfr-in.c @@ -223,50 +223,11 @@ static int xfrin_check_tsig(knot_pkt_t *packet, knot_ns_xfr_t *xfr, /*----------------------------------------------------------------------------*/ -static int xfrin_parse(knot_pkt_t **dst, uint8_t *wire, size_t wire_size) -{ - assert(dst != NULL); - - int ret = KNOT_EOK; - knot_pkt_t *pkt = knot_pkt_new(wire, wire_size, NULL); - if (pkt == NULL) { - knot_pkt_free(&pkt); - return KNOT_ENOMEM; - } - - /* This is important, don't merge RRs together. The SOAs are ordered - * in a special way for a reason. */ - ret = knot_pkt_parse(pkt, KNOT_PF_NO_MERGE); - if (ret != KNOT_EOK) { - knot_pkt_free(&pkt); - return ret; - } - - // check if the response is OK - if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) { - knot_pkt_free(&pkt); - return KNOT_EXFRREFUSED; - } - - // check if the TC bit is set (it must not be) - if (knot_wire_get_tc(pkt->wire)) { - knot_pkt_free(&pkt); - return KNOT_EMALF; - } - - *dst = pkt; - return KNOT_EOK; -} - static int xfrin_take_rr(const knot_pktsection_t *answer, knot_rrset_t **rr, uint16_t *cur) { int ret = KNOT_EOK; if (*cur < answer->count) { - /*! \note For now, the RRSets are allocated using malloc(), - * clearing the KNOT_PF_FREE flags takes their ownership. - */ - *rr = (knot_rrset_t *)answer->rr[*cur]; - answer->rrinfo[*cur].flags &= ~KNOT_PF_FREE; + ret = knot_rrset_copy(answer->rr[*cur], rr, NULL); *cur += 1; } else { *rr = NULL; @@ -278,23 +239,17 @@ static int xfrin_take_rr(const knot_pktsection_t *answer, knot_rrset_t **rr, uin /*----------------------------------------------------------------------------*/ -int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr, knot_zone_contents_t **zone) +int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, knot_zone_contents_t **zone) { - if (xfr->wire == NULL) { + if (pkt == NULL) { return KNOT_EINVAL; } - knot_pkt_t *packet = NULL; - int ret = xfrin_parse(&packet, xfr->wire, xfr->wire_size); - if (ret != KNOT_EOK ) { - return ret; - } - uint16_t rr_id = 0; knot_rrset_t *rr = NULL; - const knot_pktsection_t *answer = knot_pkt_section(packet, KNOT_ANSWER); + const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); - ret = xfrin_take_rr(answer, &rr, &rr_id); + int ret = xfrin_take_rr(answer, &rr, &rr_id); if (*zone == NULL) { // Transfer start, init zone if (rr->type != KNOT_RRTYPE_SOA) { @@ -302,7 +257,6 @@ int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr, knot_zone_contents_t **zone) } *zone = knot_zone_contents_new(rr->owner); if (*zone == NULL) { - knot_pkt_free(&packet); return KNOT_ENOMEM; } xfr->packet_nr = 0; @@ -318,8 +272,7 @@ int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr, knot_zone_contents_t **zone) if (rr->type == KNOT_RRTYPE_SOA && knot_node_rrset(zc.z->apex, KNOT_RRTYPE_SOA)) { // Last SOA, last message, check TSIG. - ret = xfrin_check_tsig(packet, xfr, 1); - knot_pkt_free(&packet); + ret = xfrin_check_tsig(pkt, xfr, 1); knot_rrset_free(&rr, NULL); if (ret != KNOT_EOK) { return ret; @@ -328,7 +281,6 @@ int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr, knot_zone_contents_t **zone) } else { ret = zcreator_step(&zc, rr); if (ret != KNOT_EOK) { - knot_pkt_free(&packet); knot_rrset_free(&rr, NULL); return ret; } @@ -338,34 +290,26 @@ int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr, knot_zone_contents_t **zone) assert(rr == NULL); // Check possible TSIG at the end of DNS message. - ret = xfrin_check_tsig(packet, xfr, + ret = xfrin_check_tsig(pkt, xfr, knot_ns_tsig_required(xfr->packet_nr)); - knot_pkt_free(&packet); return ret; // ret == KNOT_EOK means processing continues. } /*----------------------------------------------------------------------------*/ -int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) +int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr) { knot_changesets_t **chs = (knot_changesets_t **)(&xfr->data); - if (xfr->wire == NULL || chs == NULL) { + if (pkt == NULL || chs == NULL) { dbg_xfrin("Wrong parameters supported.\n"); return KNOT_EINVAL; } - knot_pkt_t *packet = NULL; - int ret = xfrin_parse(&packet, xfr->wire, xfr->wire_size); - if (ret != KNOT_EOK ) { - return ret; - } - uint16_t rr_id = 0; knot_rrset_t *rr = NULL; - const knot_pktsection_t *answer = knot_pkt_section(packet, KNOT_ANSWER); - ret = xfrin_take_rr(answer, &rr, &rr_id); + const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); + int ret = xfrin_take_rr(answer, &rr, &rr_id); if (ret != KNOT_EOK) { - knot_pkt_free(&packet); return KNOT_EXFRREFUSED; /* Empty, try again with AXFR */ } @@ -382,7 +326,6 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) ret = knot_changesets_init(chs); if (ret != KNOT_EOK) { knot_rrset_free(&rr, NULL); - knot_pkt_free(&packet); return ret; } @@ -421,11 +364,9 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) */ if (rr == NULL) { dbg_xfrin("Response containing only SOA,\n"); - knot_pkt_free(&packet); return XFRIN_RES_SOA_ONLY; } else if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { knot_rrset_free(&rr, NULL); - knot_pkt_free(&packet); dbg_xfrin("Fallback to AXFR.\n"); ret = XFRIN_RES_FALLBACK; return ret; @@ -538,11 +479,10 @@ dbg_xfrin_exec_verb( /*! \note [TSIG] Check TSIG, we're at the end of * transfer. */ - ret = xfrin_check_tsig(packet, xfr, 1); + ret = xfrin_check_tsig(pkt, xfr, 1); // last SOA, discard and end knot_rrset_free(&rr, NULL); - knot_pkt_free(&packet); /*! \note [TSIG] If TSIG validates, consider * transfer complete. */ @@ -624,7 +564,7 @@ dbg_xfrin_exec_verb( /*! \note Check TSIG, we're at the end of packet. It may not be * required. */ - ret = xfrin_check_tsig(packet, xfr, + ret = xfrin_check_tsig(pkt, xfr, knot_ns_tsig_required(xfr->packet_nr)); dbg_xfrin_verb("xfrin_check_tsig() returned %d\n", ret); ++xfr->packet_nr; @@ -636,7 +576,6 @@ dbg_xfrin_exec_verb( // here no RRs remain in the packet but the transfer is not finished // yet, return EOK - knot_pkt_free(&packet); return KNOT_EOK; cleanup: @@ -645,7 +584,6 @@ cleanup: dbg_xfrin_detail("Cleanup after processing IXFR/IN packet.\n"); knot_changesets_free(chs); - knot_pkt_free(&packet); xfr->data = 0; return ret; } diff --git a/src/knot/updates/xfr-in.h b/src/knot/updates/xfr-in.h index 474d2a82d3f81869e5d012f7e926f4c2e85e0c35..3a7f20654d2c9aac32c601e12c09a02abc809cd6 100644 --- a/src/knot/updates/xfr-in.h +++ b/src/knot/updates/xfr-in.h @@ -114,7 +114,7 @@ int xfrin_create_ixfr_query(const zone_t *zone, knot_pkt_t *pkt); * * \todo Refactor!!! */ -int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr, knot_zone_contents_t **zone); +int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, knot_zone_contents_t **zone); /*! * \brief Destroys the whole changesets structure. @@ -138,7 +138,7 @@ void xfrin_free_changesets(knot_changesets_t **changesets); * \retval KNOT_EMALF * \retval KNOT_ENOMEM */ -int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr); +int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr); /*! * \brief Applies changesets *with* zone shallow copy.