1999-08-20 05:35:16 +00:00
|
|
|
/*
|
2000-02-03 23:50:32 +00:00
|
|
|
* Copyright (C) 1999, 2000 Internet Software Consortium.
|
1999-08-20 05:35:16 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
|
|
|
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
|
|
|
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
|
|
* SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
/* $Id: xfrin.c,v 1.64 2000/04/17 19:22:29 explorer Exp $ */
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
1999-08-27 18:30:59 +00:00
|
|
|
#include <fcntl.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <isc/assertions.h>
|
|
|
|
#include <isc/error.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/result.h>
|
|
|
|
#include <isc/timer.h>
|
1999-10-02 02:54:16 +00:00
|
|
|
#include <isc/net.h>
|
1999-10-31 00:02:31 +00:00
|
|
|
#include <isc/print.h>
|
2000-02-25 00:52:11 +00:00
|
|
|
#include <isc/util.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/db.h>
|
|
|
|
#include <dns/dbiterator.h>
|
|
|
|
#include <dns/events.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
#include <dns/fixedname.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/journal.h>
|
|
|
|
#include <dns/log.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/name.h>
|
2000-02-24 21:47:46 +00:00
|
|
|
#include <dns/peer.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatasetiter.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/result.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
#include <dns/tcpmsg.h>
|
1999-09-10 15:01:04 +00:00
|
|
|
#include <dns/tsig.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/types.h>
|
|
|
|
#include <dns/view.h>
|
1999-10-29 02:12:01 +00:00
|
|
|
#include <dns/xfrin.h>
|
1999-10-14 01:37:00 +00:00
|
|
|
#include <dns/zone.h>
|
|
|
|
#include <dns/zt.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Incoming AXFR and IXFR.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define FAIL(code) do { result = (code); goto failure; } while (0)
|
|
|
|
#define CHECK(op) do { result = (op); \
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS) goto failure; \
|
1999-08-20 05:35:16 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The states of the *XFR state machine. We handle both IXFR and AXFR
|
|
|
|
* with a single integrated state machine because they cannot be distinguished
|
|
|
|
* immediately - an AXFR response to an IXFR request can only be detected
|
|
|
|
* when the first two (2) response RRs have already been received.
|
|
|
|
*/
|
|
|
|
typedef enum {
|
1999-12-13 03:01:53 +00:00
|
|
|
XFRST_SOAQUERY,
|
|
|
|
XFRST_GOTSOA,
|
1999-08-20 05:35:16 +00:00
|
|
|
XFRST_INITIALSOA,
|
|
|
|
XFRST_FIRSTDATA,
|
|
|
|
XFRST_IXFR_DELSOA,
|
|
|
|
XFRST_IXFR_DEL,
|
|
|
|
XFRST_IXFR_ADDSOA,
|
|
|
|
XFRST_IXFR_ADD,
|
|
|
|
XFRST_AXFR,
|
|
|
|
XFRST_END
|
|
|
|
} xfrin_state_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Incoming zone transfer context.
|
|
|
|
*/
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
struct dns_xfrin_ctx {
|
2000-03-29 05:03:07 +00:00
|
|
|
unsigned int magic;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_mem_t *mctx;
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_zone_t *zone;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
int refcount;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_task_t *task;
|
|
|
|
isc_timer_t *timer;
|
|
|
|
isc_socketmgr_t *socketmgr;
|
|
|
|
|
1999-12-02 22:33:15 +00:00
|
|
|
int connects; /* Connect in progress */
|
|
|
|
int sends; /* Send in progress */
|
|
|
|
int recvs; /* Receive in progress */
|
|
|
|
isc_boolean_t shuttingdown;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-12-02 22:33:15 +00:00
|
|
|
dns_name_t name; /* Name of zone to transfer */
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Requested transfer type (dns_rdatatype_axfr or
|
|
|
|
* dns_rdatatype_ixfr). The actual transfer type
|
|
|
|
* may differ due to IXFR->AXFR fallback.
|
|
|
|
*/
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_rdatatype_t reqtype;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 01:12:01 +00:00
|
|
|
isc_sockaddr_t masteraddr;
|
|
|
|
isc_sockaddr_t sourceaddr;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_socket_t *socket;
|
|
|
|
|
|
|
|
/* Buffer for IXFR/AXFR request message */
|
1999-08-27 18:30:59 +00:00
|
|
|
isc_buffer_t qbuffer;
|
1999-08-20 05:35:16 +00:00
|
|
|
unsigned char qbuffer_data[512];
|
|
|
|
|
|
|
|
/* Incoming reply TCP message */
|
|
|
|
dns_tcpmsg_t tcpmsg;
|
|
|
|
isc_boolean_t tcpmsg_valid;
|
|
|
|
|
|
|
|
dns_db_t *db;
|
|
|
|
dns_dbversion_t *ver;
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_diff_t diff; /* Pending database changes */
|
1999-08-20 05:35:16 +00:00
|
|
|
int difflen; /* Number of pending tuples */
|
|
|
|
|
|
|
|
xfrin_state_t state;
|
|
|
|
isc_uint32_t end_serial;
|
|
|
|
isc_boolean_t is_ixfr;
|
|
|
|
|
1999-09-10 15:01:04 +00:00
|
|
|
unsigned int nmsg; /* Number of messages recvd */
|
|
|
|
|
1999-10-08 18:37:24 +00:00
|
|
|
dns_tsigkey_t *tsigkey; /* Key used to create TSIG */
|
1999-09-10 15:01:04 +00:00
|
|
|
dns_rdata_any_tsig_t *lasttsig; /* The last TSIG */
|
|
|
|
void *tsigctx; /* TSIG verification context */
|
|
|
|
unsigned int sincetsig; /* recvd since the last TSIG */
|
1999-12-13 03:01:53 +00:00
|
|
|
dns_xfrindone_t done;
|
1999-09-10 15:01:04 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/*
|
|
|
|
* AXFR- and IXFR-specific data. Only one is used at a time
|
|
|
|
* according to the is_ixfr flag, so this could be a union,
|
|
|
|
* but keeping them separate makes it a bit simpler to clean
|
|
|
|
* things up when destroying the context.
|
|
|
|
*/
|
|
|
|
struct {
|
|
|
|
dns_addrdatasetfunc_t add_func;
|
|
|
|
dns_dbload_t *add_private;
|
|
|
|
} axfr;
|
|
|
|
|
|
|
|
struct {
|
1999-08-27 18:30:59 +00:00
|
|
|
isc_uint32_t request_serial;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_uint32_t end_serial;
|
|
|
|
dns_journal_t *journal;
|
|
|
|
|
|
|
|
} ixfr;
|
2000-02-25 00:52:11 +00:00
|
|
|
|
|
|
|
ISC_LINK(dns_xfrin_ctx_t) link;
|
|
|
|
dns_xfrinlist_t *transferlist;
|
1999-08-20 05:35:16 +00:00
|
|
|
};
|
|
|
|
|
2000-03-29 05:03:07 +00:00
|
|
|
#define XFRIN_MAGIC 0x58667269U /* XfrI. */
|
|
|
|
#define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/**************************************************************************/
|
|
|
|
/*
|
|
|
|
* Forward declarations.
|
|
|
|
*/
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
1999-08-20 05:35:16 +00:00
|
|
|
xfrin_create(isc_mem_t *mctx,
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_zone_t *zone,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_db_t *db,
|
|
|
|
isc_task_t *task,
|
1999-10-29 02:12:01 +00:00
|
|
|
isc_timermgr_t *timermgr,
|
1999-10-29 02:41:56 +00:00
|
|
|
isc_socketmgr_t *socketmgr,
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_name_t *zonename,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_rdataclass_t rdclass,
|
|
|
|
dns_rdatatype_t reqtype,
|
2000-01-28 01:12:01 +00:00
|
|
|
isc_sockaddr_t *masteraddr,
|
1999-10-08 18:37:24 +00:00
|
|
|
dns_tsigkey_t *tsigkey,
|
2000-01-28 23:48:58 +00:00
|
|
|
dns_xfrin_ctx_t **xfrp);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t axfr_init(dns_xfrin_ctx_t *xfr);
|
|
|
|
static isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
|
|
|
|
static isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_t *name, dns_ttl_t ttl,
|
|
|
|
dns_rdata_t *rdata);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr);
|
|
|
|
static isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr);
|
|
|
|
static isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr);
|
|
|
|
static isc_result_t ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_t *name, dns_ttl_t ttl,
|
|
|
|
dns_rdata_t *rdata);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t ixfr_commit(dns_xfrin_ctx_t *xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name,
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_uint32_t ttl, dns_rdata_t *rdata);
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
static void xfrin_connect_done(isc_task_t *task, isc_event_t *event);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
static void xfrin_send_done(isc_task_t *task, isc_event_t *event);
|
|
|
|
static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event);
|
|
|
|
static void xfrin_recv_done(isc_task_t *task, isc_event_t *event);
|
|
|
|
static void xfrin_timeout(isc_task_t *task, isc_event_t *event);
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static void maybe_free(dns_xfrin_ctx_t *xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static void xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, char *msg);
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t render(dns_message_t *msg, isc_buffer_t *buf);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-30 01:08:52 +00:00
|
|
|
static void
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_logv(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr,
|
1999-10-30 01:08:52 +00:00
|
|
|
const char *fmt, va_list ap);
|
|
|
|
static void
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_log1(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr,
|
1999-10-30 01:08:52 +00:00
|
|
|
const char *fmt, ...);
|
1999-10-29 22:42:44 +00:00
|
|
|
static void
|
2000-01-28 23:48:58 +00:00
|
|
|
xfrin_log(dns_xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...);
|
1999-10-29 22:42:44 +00:00
|
|
|
|
1999-10-30 01:08:52 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/**************************************************************************/
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* AXFR handling
|
|
|
|
*/
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
axfr_init(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->is_ixfr = ISC_FALSE;
|
|
|
|
|
1999-10-14 01:37:00 +00:00
|
|
|
if (xfr->db != NULL)
|
|
|
|
dns_db_detach(&xfr->db);
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(axfr_makedb(xfr, &xfr->db));
|
|
|
|
CHECK(dns_db_beginload(xfr->db, &xfr->axfr.add_func,
|
|
|
|
&xfr->axfr.add_private));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
|
1999-08-20 05:35:16 +00:00
|
|
|
return (dns_db_create(xfr->mctx, /* XXX */
|
|
|
|
"rbt", /* XXX guess */
|
|
|
|
&xfr->name,
|
|
|
|
ISC_FALSE,
|
|
|
|
xfr->rdclass,
|
|
|
|
0, NULL, /* XXX guess */
|
|
|
|
dbp));
|
|
|
|
}
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
|
|
|
|
{
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_difftuple_t *tuple = NULL;
|
1999-08-24 06:43:19 +00:00
|
|
|
CHECK(dns_difftuple_create(xfr->diff.mctx, op,
|
|
|
|
name, ttl, rdata, &tuple));
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_diff_append(&xfr->diff, &tuple);
|
|
|
|
if (++xfr->difflen > 100)
|
|
|
|
CHECK(axfr_apply(xfr));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store a set of AXFR RRs in the database. */
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
axfr_apply(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(dns_diff_load(&xfr->diff,
|
|
|
|
xfr->axfr.add_func, xfr->axfr.add_private));
|
|
|
|
xfr->difflen = 0;
|
1999-08-25 10:52:57 +00:00
|
|
|
dns_diff_clear(&xfr->diff);
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
axfr_commit(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(axfr_apply(xfr));
|
|
|
|
CHECK(dns_db_endload(xfr->db, &xfr->axfr.add_private));
|
1999-10-14 00:05:02 +00:00
|
|
|
CHECK(dns_zone_replacedb(xfr->zone, xfr->db, ISC_TRUE));
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-08-27 18:30:59 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* IXFR handling
|
|
|
|
*/
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
ixfr_init(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->is_ixfr = ISC_TRUE;
|
|
|
|
INSIST(xfr->db != NULL);
|
|
|
|
xfr->difflen = 0;
|
1999-10-29 06:36:05 +00:00
|
|
|
CHECK(dns_journal_open(xfr->mctx, dns_zone_getjournal(xfr->zone),
|
1999-10-14 00:05:02 +00:00
|
|
|
ISC_TRUE, &xfr->ixfr.journal));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
|
|
|
|
{
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_difftuple_t *tuple = NULL;
|
1999-08-24 06:43:19 +00:00
|
|
|
CHECK(dns_difftuple_create(xfr->diff.mctx, op,
|
|
|
|
name, ttl, rdata, &tuple));
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_diff_append(&xfr->diff, &tuple);
|
1999-08-20 05:35:16 +00:00
|
|
|
if (++xfr->difflen > 100)
|
|
|
|
CHECK(ixfr_apply(xfr));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply a set of IXFR changes to the database. */
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
ixfr_apply(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
if (xfr->ver == NULL) {
|
|
|
|
CHECK(dns_db_newversion(xfr->db, &xfr->ver));
|
|
|
|
CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
|
|
|
|
}
|
|
|
|
CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver));
|
|
|
|
dns_journal_writediff(xfr->ixfr.journal, &xfr->diff);
|
|
|
|
dns_diff_clear(&xfr->diff);
|
|
|
|
xfr->difflen = 0;
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
ixfr_commit(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
ixfr_apply(xfr);
|
|
|
|
if (xfr->ver != NULL) {
|
|
|
|
/* XXX enter ready-to-commit state here */
|
|
|
|
CHECK(dns_journal_commit(xfr->ixfr.journal));
|
|
|
|
dns_db_closeversion(xfr->db, &xfr->ver, ISC_TRUE);
|
|
|
|
}
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* Common AXFR/IXFR protocol code
|
|
|
|
*/
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle a single incoming resource record according to the current
|
|
|
|
* state.
|
|
|
|
*/
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr_rr(dns_xfrin_ctx_t *xfr,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_t *name, isc_uint32_t ttl, dns_rdata_t *rdata)
|
|
|
|
{
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
redo:
|
|
|
|
switch (xfr->state) {
|
1999-12-13 03:01:53 +00:00
|
|
|
case XFRST_SOAQUERY:
|
|
|
|
xfr->end_serial = dns_soa_getserial(rdata);
|
|
|
|
if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial)) {
|
2000-01-26 21:12:04 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"requested serial %u, "
|
1999-12-13 03:01:53 +00:00
|
|
|
"master has %u, not updating",
|
|
|
|
xfr->ixfr.request_serial, xfr->end_serial);
|
|
|
|
FAIL(DNS_R_UPTODATE);
|
|
|
|
}
|
|
|
|
xfr->state = XFRST_GOTSOA;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_GOTSOA:
|
|
|
|
/*
|
|
|
|
* skip other records in the answer section
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
case XFRST_INITIALSOA:
|
2000-04-07 19:41:07 +00:00
|
|
|
if (rdata->type != dns_rdatatype_soa) {
|
|
|
|
xfrin_log(xfr, ISC_LOG_ERROR,
|
|
|
|
"first RR in zone transfer must be SOA");
|
|
|
|
FAIL(DNS_R_FORMERR);
|
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
/*
|
|
|
|
* Remember the serial number in the intial SOA.
|
|
|
|
* We need it to recognize the end of an IXFR.
|
|
|
|
*/
|
|
|
|
xfr->end_serial = dns_soa_getserial(rdata);
|
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr &&
|
|
|
|
! DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial))
|
|
|
|
{
|
|
|
|
/*
|
1999-08-24 06:43:19 +00:00
|
|
|
* This must be the single SOA record that is
|
|
|
|
* sent when the current version on the master
|
|
|
|
* is not newer than the version in the request.
|
1999-08-20 05:35:16 +00:00
|
|
|
*/
|
2000-01-26 21:12:04 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"requested serial %u, "
|
1999-10-29 22:42:44 +00:00
|
|
|
"master has %u, not updating",
|
|
|
|
xfr->ixfr.request_serial, xfr->end_serial);
|
1999-08-20 05:35:16 +00:00
|
|
|
FAIL(DNS_R_UPTODATE);
|
1999-08-27 18:30:59 +00:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->state = XFRST_FIRSTDATA;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_FIRSTDATA:
|
|
|
|
/*
|
|
|
|
* If the transfer begins with one SOA record, it is an AXFR,
|
|
|
|
* if it begins with two SOAs, it is an IXFR.
|
|
|
|
*/
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
2000-03-20 21:07:48 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"got incremental response");
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(ixfr_init(xfr));
|
|
|
|
xfr->state = XFRST_IXFR_DELSOA;
|
|
|
|
} else {
|
2000-03-20 21:07:48 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"got nonincremental response");
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(axfr_init(xfr));
|
|
|
|
xfr->state = XFRST_AXFR;
|
|
|
|
}
|
1999-08-27 18:30:59 +00:00
|
|
|
goto redo;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
case XFRST_IXFR_DELSOA:
|
|
|
|
INSIST(rdata->type == dns_rdatatype_soa);
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
|
|
|
|
xfr->state = XFRST_IXFR_DEL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_IXFR_DEL:
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
|
|
|
isc_uint32_t soa_serial = dns_soa_getserial(rdata);
|
|
|
|
xfr->state = XFRST_IXFR_ADDSOA;
|
|
|
|
xfr->ixfr.end_serial = soa_serial;
|
|
|
|
goto redo;
|
|
|
|
}
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_IXFR_ADDSOA:
|
|
|
|
INSIST(rdata->type == dns_rdatatype_soa);
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
|
|
|
xfr->state = XFRST_IXFR_ADD;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_IXFR_ADD:
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
|
|
|
isc_uint32_t soa_serial = dns_soa_getserial(rdata);
|
1999-08-27 18:30:59 +00:00
|
|
|
CHECK(ixfr_commit(xfr));
|
1999-08-20 05:35:16 +00:00
|
|
|
if (soa_serial == xfr->end_serial) {
|
|
|
|
xfr->state = XFRST_END;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
xfr->state = XFRST_IXFR_DELSOA;
|
|
|
|
goto redo;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_AXFR:
|
|
|
|
CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
1999-08-27 18:30:59 +00:00
|
|
|
CHECK(axfr_commit(xfr));
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->state = XFRST_END;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XFRST_END:
|
|
|
|
FAIL(DNS_R_EXTRADATA);
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
|
|
|
break;
|
|
|
|
}
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
isc_result_t
|
|
|
|
dns_xfrin_create(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
|
|
|
|
isc_mem_t *mctx, isc_timermgr_t *timermgr,
|
|
|
|
isc_socketmgr_t *socketmgr, isc_task_t *task,
|
|
|
|
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
|
1999-10-29 02:12:01 +00:00
|
|
|
{
|
1999-10-14 02:12:03 +00:00
|
|
|
dns_name_t *zonename;
|
2000-02-25 00:52:11 +00:00
|
|
|
dns_xfrin_ctx_t *xfr, *x;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_db_t *db = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_rdatatype_t xfrtype;
|
1999-10-08 18:37:24 +00:00
|
|
|
dns_tsigkey_t *key = NULL;
|
2000-04-08 04:42:42 +00:00
|
|
|
dns_name_t *keyname = NULL;
|
2000-02-25 00:52:11 +00:00
|
|
|
isc_netaddr_t masterip;
|
|
|
|
dns_peer_t *peer = NULL;
|
2000-02-25 17:34:05 +00:00
|
|
|
int maxtransfersin, maxtransfersperns;
|
|
|
|
int nxfrsin, nxfrsperns;
|
2000-02-25 00:52:11 +00:00
|
|
|
dns_xfrinlist_t *transferlist;
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
REQUIRE(xfrp != NULL && *xfrp == NULL);
|
1999-10-29 22:42:44 +00:00
|
|
|
|
1999-10-14 02:12:03 +00:00
|
|
|
zonename = dns_zone_getorigin(zone);
|
1999-10-30 01:08:52 +00:00
|
|
|
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_log1(ISC_LOG_INFO, zonename, masteraddr, "starting");
|
1999-10-30 01:08:52 +00:00
|
|
|
|
2000-02-25 00:52:11 +00:00
|
|
|
/*
|
|
|
|
* Find any configured information about the server we are about
|
|
|
|
* to transfer from.
|
|
|
|
*/
|
|
|
|
isc_netaddr_fromsockaddr(&masterip, masteraddr);
|
|
|
|
(void) dns_peerlist_peerbyaddr(dns_zone_getview(zone)->peers,
|
|
|
|
&masterip, &peer);
|
|
|
|
|
1999-10-14 00:05:02 +00:00
|
|
|
result = dns_zone_getdb(zone, &db);
|
|
|
|
if (result == DNS_R_NOTLOADED)
|
|
|
|
INSIST(db == NULL);
|
|
|
|
else
|
|
|
|
CHECK(result);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-02-24 21:47:46 +00:00
|
|
|
/*
|
2000-03-20 19:42:21 +00:00
|
|
|
* Decide whether we should request IXFR or AXFR.
|
2000-02-24 21:47:46 +00:00
|
|
|
*/
|
1999-10-14 00:05:02 +00:00
|
|
|
if (db == NULL) {
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
|
1999-10-30 01:08:52 +00:00
|
|
|
"no database exists yet, "
|
|
|
|
"requesting AXFR of initial version");
|
1999-08-27 18:30:59 +00:00
|
|
|
xfrtype = dns_rdatatype_axfr;
|
1999-08-20 05:35:16 +00:00
|
|
|
} else {
|
2000-02-24 21:47:46 +00:00
|
|
|
isc_boolean_t use_ixfr = ISC_TRUE;
|
2000-02-25 00:52:11 +00:00
|
|
|
if (peer != NULL &&
|
2000-03-29 05:03:07 +00:00
|
|
|
dns_peer_getrequestixfr(peer, &use_ixfr) ==
|
|
|
|
ISC_R_SUCCESS) {
|
2000-03-20 19:42:21 +00:00
|
|
|
; /* Using peer setting */
|
|
|
|
} else {
|
2000-04-07 22:30:43 +00:00
|
|
|
use_ixfr = dns_zone_getview(zone)->requestixfr;
|
2000-03-20 19:42:21 +00:00
|
|
|
}
|
|
|
|
if (use_ixfr == ISC_FALSE) {
|
2000-02-24 21:47:46 +00:00
|
|
|
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
|
2000-03-20 19:42:21 +00:00
|
|
|
"IXFR disabled, requesting AXFR");
|
2000-02-24 21:47:46 +00:00
|
|
|
xfrtype = dns_rdatatype_axfr;
|
|
|
|
} else {
|
|
|
|
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
|
2000-03-20 19:42:21 +00:00
|
|
|
"requesting IXFR");
|
2000-02-24 21:47:46 +00:00
|
|
|
xfrtype = dns_rdatatype_ixfr;
|
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
2000-02-25 00:52:11 +00:00
|
|
|
/*
|
|
|
|
* Determine the maximum number of simultaneous transfers
|
|
|
|
* allowed for this server, then count the number of
|
|
|
|
* transfers already in progress and fail if the quota
|
|
|
|
* is already full.
|
|
|
|
*
|
|
|
|
* Count the number of transfers that are in progress from
|
|
|
|
* this master. We linearly scan a list of all transfers;
|
|
|
|
* if this turns out to be too slow, we could hash on the
|
|
|
|
* master address.
|
|
|
|
*
|
|
|
|
* Note that we must keep the transfer list locked for an
|
|
|
|
* awkwardly long time because the scanning of the list
|
|
|
|
* and the creation of a new entry must be done atomically,
|
|
|
|
* and we don't want to create the transfer object until we
|
|
|
|
* know there is quota available.
|
|
|
|
*/
|
2000-02-25 17:34:05 +00:00
|
|
|
maxtransfersin =
|
|
|
|
dns_zonemgr_getttransfersin(dns_zone_getmgr(zone));
|
|
|
|
maxtransfersperns =
|
|
|
|
dns_zonemgr_getttransfersperns(dns_zone_getmgr(zone));
|
2000-02-25 00:52:11 +00:00
|
|
|
if (peer != NULL) {
|
2000-02-25 17:34:05 +00:00
|
|
|
(void) dns_peer_gettransfers(peer, &maxtransfersperns);
|
2000-02-25 00:52:11 +00:00
|
|
|
}
|
2000-04-08 04:42:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine if we should attempt to sign the request with TSIG.
|
|
|
|
*/
|
|
|
|
if (peer != NULL && dns_peer_getkey(peer, &keyname) == ISC_R_SUCCESS) {
|
|
|
|
dns_view_t *view = dns_zone_getview(zone);
|
|
|
|
result = dns_tsigkey_find(&key, keyname, NULL,
|
|
|
|
view->statickeys);
|
|
|
|
if (result == ISC_R_NOTFOUND)
|
|
|
|
result = dns_tsigkey_find(&key, keyname, NULL,
|
|
|
|
view->dynamickeys);
|
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
|
|
|
|
goto failure;
|
|
|
|
}
|
2000-02-25 00:52:11 +00:00
|
|
|
|
|
|
|
transferlist = dns_zonemgr_gettransferlist(dns_zone_getmgr(zone));
|
|
|
|
LOCK(&transferlist->lock);
|
2000-02-25 17:34:05 +00:00
|
|
|
nxfrsin = nxfrsperns = 0;
|
2000-02-25 00:52:11 +00:00
|
|
|
for (x = ISC_LIST_HEAD(transferlist->transfers);
|
|
|
|
x != NULL;
|
|
|
|
x = ISC_LIST_NEXT(x, link))
|
|
|
|
{
|
|
|
|
isc_netaddr_t xip;
|
|
|
|
isc_netaddr_fromsockaddr(&xip, &x->masteraddr);
|
2000-02-25 17:34:05 +00:00
|
|
|
nxfrsin++;
|
2000-02-25 00:52:11 +00:00
|
|
|
if (isc_netaddr_equal(&xip, &masterip))
|
2000-02-25 17:34:05 +00:00
|
|
|
nxfrsperns++;
|
2000-02-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
2000-02-25 17:34:05 +00:00
|
|
|
if (nxfrsin >= maxtransfersin || nxfrsperns >= maxtransfersperns) {
|
2000-02-25 00:52:11 +00:00
|
|
|
result = ISC_R_QUOTA;
|
|
|
|
xfrin_log1(ISC_LOG_INFO, zonename, masteraddr,
|
|
|
|
"deferred: %s", isc_result_totext(result));
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = xfrin_create(mctx,
|
|
|
|
zone,
|
|
|
|
db,
|
|
|
|
task,
|
|
|
|
timermgr,
|
|
|
|
socketmgr,
|
|
|
|
zonename,
|
|
|
|
dns_zone_getclass(zone), xfrtype,
|
|
|
|
masteraddr, key, &xfr);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
xfr->transferlist = transferlist;
|
|
|
|
ISC_LIST_APPEND(transferlist->transfers, xfr, link);
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
UNLOCK(&transferlist->lock);
|
|
|
|
CHECK(result);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
CHECK(xfrin_start(xfr));
|
1999-12-13 03:01:53 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr->done = done;
|
|
|
|
xfr->refcount++;
|
|
|
|
*xfrp = xfr;
|
1999-12-13 03:01:53 +00:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
failure:
|
1999-10-25 12:18:43 +00:00
|
|
|
if (db != NULL)
|
|
|
|
dns_db_detach(&db);
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_log1(ISC_LOG_ERROR, zonename, masteraddr,
|
1999-10-30 01:08:52 +00:00
|
|
|
"zone transfer setup failed");
|
2000-01-28 23:48:58 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
|
|
|
|
if (! xfr->shuttingdown)
|
|
|
|
xfrin_fail(xfr, ISC_R_CANCELED, "shut down");
|
|
|
|
}
|
|
|
|
|
|
|
|
void dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
|
|
|
|
dns_xfrin_ctx_t *xfr = *xfrp;
|
|
|
|
INSIST(xfr->refcount > 0);
|
|
|
|
xfr->refcount--;
|
|
|
|
maybe_free(xfr);
|
|
|
|
*xfrp = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-01-28 23:48:58 +00:00
|
|
|
xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, char *msg) {
|
1999-08-20 05:35:16 +00:00
|
|
|
if (result != DNS_R_UPTODATE) {
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
|
|
|
|
msg, isc_result_totext(result));
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
1999-12-02 22:33:15 +00:00
|
|
|
if (xfr->connects > 0) {
|
|
|
|
isc_socket_cancel(xfr->socket, xfr->task,
|
|
|
|
ISC_SOCKCANCEL_CONNECT);
|
|
|
|
} else if (xfr->recvs > 0) {
|
|
|
|
dns_tcpmsg_cancelread(&xfr->tcpmsg);
|
|
|
|
} else if (xfr->sends > 0) {
|
|
|
|
isc_socket_cancel(xfr->socket, xfr->task,
|
|
|
|
ISC_SOCKCANCEL_SEND);
|
|
|
|
}
|
2000-01-28 23:48:58 +00:00
|
|
|
if (xfr->done != NULL) {
|
1999-12-13 03:01:53 +00:00
|
|
|
(xfr->done)(xfr->zone, result);
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr->done = NULL;
|
|
|
|
}
|
2000-03-29 05:03:07 +00:00
|
|
|
xfr->shuttingdown = ISC_TRUE;
|
1999-12-02 22:33:15 +00:00
|
|
|
maybe_free(xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
1999-08-20 05:35:16 +00:00
|
|
|
xfrin_create(isc_mem_t *mctx,
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_zone_t *zone,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_db_t *db,
|
|
|
|
isc_task_t *task,
|
1999-10-29 02:12:01 +00:00
|
|
|
isc_timermgr_t *timermgr,
|
1999-10-29 02:41:56 +00:00
|
|
|
isc_socketmgr_t *socketmgr,
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_name_t *zonename,
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_rdataclass_t rdclass,
|
|
|
|
dns_rdatatype_t reqtype,
|
2000-01-28 01:12:01 +00:00
|
|
|
isc_sockaddr_t *masteraddr,
|
1999-10-08 18:37:24 +00:00
|
|
|
dns_tsigkey_t *tsigkey,
|
2000-01-28 23:48:58 +00:00
|
|
|
dns_xfrin_ctx_t **xfrp)
|
1999-08-20 05:35:16 +00:00
|
|
|
{
|
2000-01-28 23:48:58 +00:00
|
|
|
dns_xfrin_ctx_t *xfr = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_result_t result;
|
2000-01-31 22:55:04 +00:00
|
|
|
isc_interval_t maxinterval, idleinterval;
|
|
|
|
isc_time_t expires;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
xfr = isc_mem_get(mctx, sizeof(*xfr));
|
|
|
|
if (xfr == NULL)
|
2000-04-06 22:03:35 +00:00
|
|
|
return (ISC_R_NOMEMORY);
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->mctx = mctx;
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr->refcount = 0;
|
1999-10-14 00:05:02 +00:00
|
|
|
xfr->zone = NULL;
|
2000-02-10 01:12:15 +00:00
|
|
|
dns_zone_iattach(zone, &xfr->zone);
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr->task = NULL;
|
|
|
|
isc_task_attach(task, &xfr->task);
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->timer = NULL;
|
|
|
|
xfr->socketmgr = socketmgr;
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr->done = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-12-02 22:33:15 +00:00
|
|
|
xfr->connects = 0;
|
|
|
|
xfr->sends = 0;
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->recvs = 0;
|
1999-12-02 22:33:15 +00:00
|
|
|
xfr->shuttingdown = ISC_FALSE;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
dns_name_init(&xfr->name, NULL);
|
|
|
|
xfr->rdclass = rdclass;
|
|
|
|
xfr->reqtype = reqtype;
|
|
|
|
|
|
|
|
/* sockaddr */
|
|
|
|
xfr->socket = NULL;
|
|
|
|
/* qbuffer */
|
|
|
|
/* qbuffer_data */
|
|
|
|
/* tcpmsg */
|
|
|
|
xfr->tcpmsg_valid = ISC_FALSE;
|
|
|
|
|
1999-10-25 12:18:43 +00:00
|
|
|
xfr->db = NULL;
|
|
|
|
if (db != NULL)
|
|
|
|
dns_db_attach(db, &xfr->db);
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->ver = NULL;
|
|
|
|
dns_diff_init(xfr->mctx, &xfr->diff);
|
|
|
|
xfr->difflen = 0;
|
|
|
|
|
|
|
|
xfr->state = XFRST_INITIALSOA;
|
|
|
|
/* end_serial */
|
1999-09-10 15:01:04 +00:00
|
|
|
|
|
|
|
xfr->nmsg = 0;
|
|
|
|
|
|
|
|
xfr->tsigkey = tsigkey;
|
|
|
|
xfr->lasttsig = NULL;
|
|
|
|
xfr->tsigctx = NULL;
|
|
|
|
xfr->sincetsig = 0;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/* is_ixfr */
|
|
|
|
|
|
|
|
/* ixfr.request_serial */
|
|
|
|
/* ixfr.end_serial */
|
|
|
|
xfr->ixfr.journal = NULL;
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->axfr.add_func = NULL;
|
|
|
|
xfr->axfr.add_private = NULL;
|
|
|
|
|
2000-02-25 00:52:11 +00:00
|
|
|
ISC_LINK_INIT(xfr, link);
|
|
|
|
xfr->transferlist = NULL;
|
|
|
|
|
1999-10-14 00:05:02 +00:00
|
|
|
CHECK(dns_name_dup(zonename, mctx, &xfr->name));
|
2000-01-31 22:55:04 +00:00
|
|
|
|
|
|
|
isc_interval_set(&maxinterval, dns_zone_getmaxxfrin(xfr->zone), 0);
|
|
|
|
CHECK(isc_time_nowplusinterval(&expires, &maxinterval));
|
|
|
|
isc_interval_set(&idleinterval, dns_zone_getidlein(xfr->zone), 0);
|
|
|
|
|
1999-10-29 02:12:01 +00:00
|
|
|
CHECK(isc_timer_create(timermgr, isc_timertype_once,
|
2000-01-31 22:55:04 +00:00
|
|
|
&expires, &idleinterval, task,
|
1999-08-20 05:35:16 +00:00
|
|
|
xfrin_timeout, xfr, &xfr->timer));
|
|
|
|
|
2000-01-28 01:12:01 +00:00
|
|
|
xfr->masteraddr = *masteraddr;
|
2000-01-31 18:00:07 +00:00
|
|
|
|
|
|
|
switch (isc_sockaddr_pf(masteraddr)) {
|
|
|
|
case PF_INET:
|
|
|
|
xfr->sourceaddr = *dns_zone_getxfrsource4(zone);
|
|
|
|
break;
|
|
|
|
case PF_INET6:
|
|
|
|
xfr->sourceaddr = *dns_zone_getxfrsource6(zone);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
|
|
|
}
|
2000-01-28 01:12:01 +00:00
|
|
|
|
1999-08-24 06:43:19 +00:00
|
|
|
isc_buffer_init(&xfr->qbuffer, xfr->qbuffer_data,
|
|
|
|
sizeof(xfr->qbuffer_data),
|
1999-08-20 05:35:16 +00:00
|
|
|
ISC_BUFFERTYPE_BINARY);
|
|
|
|
|
2000-03-29 05:03:07 +00:00
|
|
|
xfr->magic = XFRIN_MAGIC;
|
1999-08-20 05:35:16 +00:00
|
|
|
*xfrp = xfr;
|
2000-04-06 22:03:35 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
failure:
|
1999-12-02 22:33:15 +00:00
|
|
|
xfrin_fail(xfr, result, "creating transfer context");
|
1999-08-20 05:35:16 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2000-02-02 01:01:24 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
xfrin_start(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-24 06:43:19 +00:00
|
|
|
CHECK(isc_socket_create(xfr->socketmgr,
|
2000-01-31 18:00:07 +00:00
|
|
|
isc_sockaddr_pf(&xfr->sourceaddr),
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_sockettype_tcp,
|
|
|
|
&xfr->socket));
|
2000-01-28 01:12:01 +00:00
|
|
|
CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr));
|
|
|
|
CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
|
1999-08-20 05:35:16 +00:00
|
|
|
xfrin_connect_done, xfr));
|
1999-12-02 22:33:15 +00:00
|
|
|
xfr->connects++;
|
2000-01-28 23:48:58 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
xfrin_fail(xfr, result, "setting up socket");
|
2000-01-28 23:48:58 +00:00
|
|
|
return (result);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX the resolver could use this, too */
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
1999-08-20 05:35:16 +00:00
|
|
|
render(dns_message_t *msg, isc_buffer_t *buf) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(dns_message_renderbegin(msg, buf));
|
1999-12-22 03:22:59 +00:00
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
|
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
|
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0));
|
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0));
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(dns_message_renderend(msg));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-08-27 18:30:59 +00:00
|
|
|
* A connection has been established.
|
1999-08-20 05:35:16 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
|
|
|
|
isc_socket_connev_t *cev = (isc_socket_connev_t *) event;
|
2000-04-17 19:22:44 +00:00
|
|
|
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t evresult = cev->result;
|
|
|
|
isc_result_t result;
|
2000-03-29 05:03:07 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
UNUSED(task);
|
|
|
|
|
|
|
|
INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT);
|
1999-12-02 22:33:15 +00:00
|
|
|
isc_event_free(&event);
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-12-02 22:33:15 +00:00
|
|
|
xfr->connects--;
|
2000-01-28 23:48:58 +00:00
|
|
|
if (xfr->shuttingdown) {
|
|
|
|
maybe_free(xfr);
|
1999-12-02 22:33:15 +00:00
|
|
|
return;
|
2000-01-28 23:48:58 +00:00
|
|
|
}
|
1999-12-02 22:33:15 +00:00
|
|
|
|
|
|
|
CHECK(evresult);
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "connected");
|
|
|
|
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
|
|
|
|
xfr->tcpmsg_valid = ISC_TRUE;
|
|
|
|
|
|
|
|
CHECK(xfrin_send_request(xfr));
|
|
|
|
failure:
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_fail(xfr, result, "connect");
|
1999-08-27 18:30:59 +00:00
|
|
|
}
|
|
|
|
|
1999-10-28 19:11:33 +00:00
|
|
|
/*
|
|
|
|
* Convert a tuple into a dns_name_t suitable for inserting
|
|
|
|
* into the given dns_message_t.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target)
|
|
|
|
{
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-10-28 19:11:33 +00:00
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
dns_rdatalist_t *rdl = NULL;
|
|
|
|
dns_rdataset_t *rds = NULL;
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
|
|
|
REQUIRE(target != NULL && *target == NULL);
|
|
|
|
|
|
|
|
CHECK(dns_message_gettemprdata(msg, &rdata));
|
|
|
|
dns_rdata_init(rdata);
|
|
|
|
*rdata = tuple->rdata; /* Struct assignment. */
|
|
|
|
|
|
|
|
CHECK(dns_message_gettemprdatalist(msg, &rdl));
|
|
|
|
dns_rdatalist_init(rdl);
|
|
|
|
rdl->type = tuple->rdata.type;
|
|
|
|
rdl->rdclass = tuple->rdata.rdclass;
|
|
|
|
rdl->ttl = tuple->ttl;
|
|
|
|
ISC_LIST_APPEND(rdl->rdata, rdata, link);
|
|
|
|
|
|
|
|
CHECK(dns_message_gettemprdataset(msg, &rds));
|
|
|
|
dns_rdataset_init(rds);
|
|
|
|
CHECK(dns_rdatalist_tordataset(rdl, rds));
|
|
|
|
|
|
|
|
CHECK(dns_message_gettempname(msg, &name));
|
|
|
|
dns_name_init(name, NULL);
|
|
|
|
dns_name_clone(&tuple->name, name);
|
|
|
|
ISC_LIST_APPEND(name->list, rds, link);
|
|
|
|
|
|
|
|
*target = name;
|
|
|
|
failure:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* Build an *XFR request and send its length prefix.
|
|
|
|
*/
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2000-01-28 23:48:58 +00:00
|
|
|
xfrin_send_request(dns_xfrin_ctx_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_region_t region;
|
|
|
|
isc_region_t lregion;
|
1999-10-28 01:10:38 +00:00
|
|
|
dns_rdataset_t *qrdataset = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_message_t *msg = NULL;
|
|
|
|
unsigned char length[2];
|
|
|
|
dns_difftuple_t *soatuple = NULL;
|
1999-10-28 00:02:08 +00:00
|
|
|
dns_name_t *qname = NULL;
|
1999-10-28 19:11:33 +00:00
|
|
|
dns_dbversion_t *ver = NULL;
|
1999-10-29 02:41:56 +00:00
|
|
|
dns_name_t *msgsoaname = NULL;
|
1999-10-28 01:10:38 +00:00
|
|
|
|
|
|
|
/* Create the request message */
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &msg));
|
1999-09-10 15:01:04 +00:00
|
|
|
msg->tsigkey = xfr->tsigkey;
|
1999-10-28 01:10:38 +00:00
|
|
|
|
|
|
|
/* Create a name for the question section. */
|
1999-10-28 00:02:08 +00:00
|
|
|
dns_message_gettempname(msg, &qname);
|
|
|
|
dns_name_init(qname, NULL);
|
|
|
|
dns_name_clone(&xfr->name, qname);
|
1999-10-28 01:10:38 +00:00
|
|
|
|
|
|
|
/* Formulate the question and attach it to the question name. */
|
|
|
|
dns_message_gettemprdataset(msg, &qrdataset);
|
|
|
|
dns_rdataset_init(qrdataset);
|
|
|
|
dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype);
|
|
|
|
ISC_LIST_APPEND(qname->list, qrdataset, link);
|
|
|
|
|
1999-10-28 00:02:08 +00:00
|
|
|
dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr) {
|
1999-10-28 19:11:33 +00:00
|
|
|
/* Get the SOA and add it to the authority section. */
|
1999-08-20 05:35:16 +00:00
|
|
|
/* XXX is using the current version the right thing? */
|
|
|
|
dns_db_currentversion(xfr->db, &ver);
|
1999-10-28 19:11:33 +00:00
|
|
|
CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx,
|
|
|
|
DNS_DIFFOP_EXISTS, &soatuple));
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata);
|
2000-01-26 21:12:04 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"requesting IXFR for serial %u",
|
1999-10-29 22:42:44 +00:00
|
|
|
xfr->ixfr.request_serial);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-28 19:11:33 +00:00
|
|
|
CHECK(tuple2msgname(soatuple, msg, &msgsoaname));
|
|
|
|
dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
msg->id = ('b' << 8) | '9'; /* Arbitrary */
|
1999-09-10 15:01:04 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(render(msg, &xfr->qbuffer));
|
|
|
|
|
1999-09-10 15:01:04 +00:00
|
|
|
/* Save the query TSIG and don't let message_destroy free it */
|
|
|
|
xfr->lasttsig = msg->tsig;
|
|
|
|
msg->tsig = NULL;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_buffer_used(&xfr->qbuffer, ®ion);
|
|
|
|
INSIST(region.length <= 65535);
|
|
|
|
|
|
|
|
length[0] = region.length >> 8;
|
|
|
|
length[1] = region.length & 0xFF;
|
|
|
|
lregion.base = length;
|
|
|
|
lregion.length = 2;
|
|
|
|
CHECK(isc_socket_send(xfr->socket, &lregion, xfr->task,
|
|
|
|
xfrin_sendlen_done, xfr));
|
1999-12-02 22:33:15 +00:00
|
|
|
xfr->sends++;
|
1999-10-28 19:11:33 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
1999-10-28 19:11:33 +00:00
|
|
|
if (msg != NULL)
|
|
|
|
dns_message_destroy(&msg);
|
1999-08-20 05:35:16 +00:00
|
|
|
if (soatuple != NULL)
|
|
|
|
dns_difftuple_free(&soatuple);
|
1999-10-28 19:11:33 +00:00
|
|
|
if (ver != NULL)
|
|
|
|
dns_db_closeversion(xfr->db, &ver, ISC_FALSE);
|
1999-08-27 18:30:59 +00:00
|
|
|
return (result);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX there should be library support for sending DNS TCP messages */
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
static void
|
|
|
|
xfrin_sendlen_done(isc_task_t *task, isc_event_t *event)
|
|
|
|
{
|
|
|
|
isc_socketevent_t *sev = (isc_socketevent_t *) event;
|
2000-04-17 19:22:44 +00:00
|
|
|
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t evresult = sev->result;
|
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_region_t region;
|
|
|
|
|
2000-03-29 05:03:07 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
UNUSED(task);
|
|
|
|
|
|
|
|
INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
|
1999-12-02 22:33:15 +00:00
|
|
|
isc_event_free(&event);
|
|
|
|
|
|
|
|
xfr->sends--;
|
2000-01-28 23:48:58 +00:00
|
|
|
if (xfr->shuttingdown) {
|
|
|
|
maybe_free(xfr);
|
1999-12-02 22:33:15 +00:00
|
|
|
return;
|
2000-01-28 23:48:58 +00:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix");
|
1999-12-02 22:33:15 +00:00
|
|
|
CHECK(evresult);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
isc_buffer_used(&xfr->qbuffer, ®ion);
|
|
|
|
CHECK(isc_socket_send(xfr->socket, ®ion, xfr->task,
|
|
|
|
xfrin_send_done, xfr));
|
1999-12-02 22:33:15 +00:00
|
|
|
xfr->sends++;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_fail(xfr, result, "sending request length prefix");
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
xfrin_send_done(isc_task_t *task, isc_event_t *event)
|
|
|
|
{
|
|
|
|
isc_socketevent_t *sev = (isc_socketevent_t *) event;
|
2000-04-17 19:22:44 +00:00
|
|
|
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-03-29 05:03:07 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
UNUSED(task);
|
|
|
|
|
|
|
|
INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
|
1999-12-02 22:33:15 +00:00
|
|
|
|
|
|
|
xfr->sends--;
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(sev->result);
|
|
|
|
|
|
|
|
CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
|
|
|
|
xfrin_recv_done, xfr));
|
|
|
|
xfr->recvs++;
|
|
|
|
failure:
|
1999-08-25 10:52:57 +00:00
|
|
|
isc_event_free(&event);
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_fail(xfr, result, "sending request data");
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
|
2000-04-17 19:22:44 +00:00
|
|
|
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) ev->ev_arg;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_message_t *msg = NULL;
|
|
|
|
dns_name_t *name;
|
|
|
|
dns_tcpmsg_t *tcpmsg;
|
2000-03-29 05:03:07 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
UNUSED(task);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
INSIST(ev->ev_type == DNS_EVENT_TCPMSG);
|
|
|
|
tcpmsg = ev->ev_sender;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_event_free(&ev);
|
|
|
|
|
|
|
|
xfr->recvs--;
|
2000-01-28 23:48:58 +00:00
|
|
|
if (xfr->shuttingdown) {
|
|
|
|
maybe_free(xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
return;
|
2000-01-28 23:48:58 +00:00
|
|
|
}
|
1999-09-10 15:01:04 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(tcpmsg->result);
|
|
|
|
|
1999-12-06 18:00:31 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes",
|
|
|
|
tcpmsg->buffer.used);
|
|
|
|
|
2000-01-31 22:55:04 +00:00
|
|
|
CHECK(isc_timer_touch(xfr->timer));
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTPARSE, &msg));
|
1999-09-10 15:01:04 +00:00
|
|
|
|
|
|
|
msg->tsigkey = xfr->tsigkey;
|
|
|
|
msg->querytsig = xfr->lasttsig;
|
|
|
|
msg->tsigctx = xfr->tsigctx;
|
|
|
|
if (xfr->nmsg > 0)
|
|
|
|
msg->tcp_continuation = 1;
|
|
|
|
|
1999-12-13 03:01:53 +00:00
|
|
|
result = dns_message_parse(msg, &tcpmsg->buffer, ISC_TRUE);
|
1999-08-27 18:30:59 +00:00
|
|
|
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror) {
|
|
|
|
if (result == ISC_R_SUCCESS)
|
1999-12-13 03:01:53 +00:00
|
|
|
result = ISC_RESULTCLASS_DNSRCODE + msg->rcode; /*XXX*/
|
|
|
|
if (xfr->reqtype == dns_rdatatype_axfr ||
|
|
|
|
xfr->reqtype == dns_rdatatype_soa)
|
1999-08-27 18:30:59 +00:00
|
|
|
FAIL(result);
|
1999-12-02 05:11:28 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR",
|
1999-08-27 18:30:59 +00:00
|
|
|
isc_result_totext(result));
|
|
|
|
dns_message_destroy(&msg);
|
1999-12-13 03:01:53 +00:00
|
|
|
xfr->reqtype = dns_rdatatype_soa;
|
|
|
|
xfr->state = XFRST_SOAQUERY;
|
1999-08-27 18:30:59 +00:00
|
|
|
CHECK(xfrin_send_request(xfr));
|
|
|
|
return;
|
|
|
|
}
|
2000-04-08 04:42:42 +00:00
|
|
|
|
|
|
|
result = dns_message_checksig(msg, dns_zone_getview(xfr->zone));
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s",
|
|
|
|
isc_result_totext(result));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
|
2000-04-06 22:03:35 +00:00
|
|
|
result == ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
result = dns_message_nextname(msg, DNS_SECTION_ANSWER))
|
|
|
|
{
|
|
|
|
dns_rdataset_t *rds;
|
|
|
|
|
|
|
|
name = NULL;
|
|
|
|
dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
|
2000-03-29 21:01:30 +00:00
|
|
|
if (!dns_name_issubdomain(name, &xfr->name)) {
|
|
|
|
/*
|
|
|
|
* Ignore out-of-zone data.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
for (rds = ISC_LIST_HEAD(name->list);
|
|
|
|
rds != NULL;
|
|
|
|
rds = ISC_LIST_NEXT(rds, link))
|
|
|
|
{
|
|
|
|
for (result = dns_rdataset_first(rds);
|
2000-04-06 22:03:35 +00:00
|
|
|
result == ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
result = dns_rdataset_next(rds))
|
|
|
|
{
|
|
|
|
dns_rdata_t rdata;
|
|
|
|
dns_rdataset_current(rds, &rdata);
|
|
|
|
CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_NOMORE)
|
1999-08-20 05:35:16 +00:00
|
|
|
goto failure;
|
1999-09-10 15:01:04 +00:00
|
|
|
|
|
|
|
if (msg->tsig != NULL) {
|
|
|
|
/* Reset the counter */
|
|
|
|
xfr->sincetsig = 0;
|
|
|
|
|
|
|
|
/* Free the last tsig, if there is one */
|
|
|
|
if (xfr->lasttsig != NULL) {
|
|
|
|
dns_rdata_freestruct(xfr->lasttsig);
|
|
|
|
isc_mem_put(xfr->mctx, xfr->lasttsig,
|
|
|
|
sizeof(*xfr->lasttsig));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the last tsig pointer */
|
|
|
|
xfr->lasttsig = msg->tsig;
|
|
|
|
|
|
|
|
/* Reset msg->tsig so it doesn't get freed */
|
|
|
|
msg->tsig = NULL;
|
1999-10-28 01:10:38 +00:00
|
|
|
} else if (msg->tsigkey != NULL) {
|
1999-09-10 15:01:04 +00:00
|
|
|
xfr->sincetsig++;
|
1999-10-28 01:10:38 +00:00
|
|
|
if (xfr->sincetsig > 100 ||
|
|
|
|
xfr->nmsg == 0 || xfr->state == XFRST_END)
|
|
|
|
{
|
1999-09-10 15:01:04 +00:00
|
|
|
result = DNS_R_EXPECTEDTSIG;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the number of messages received */
|
|
|
|
xfr->nmsg++;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-09-10 15:01:04 +00:00
|
|
|
/* Reset msg->querytsig so it doesn't get freed */
|
|
|
|
msg->querytsig = NULL;
|
|
|
|
|
|
|
|
/* Copy the context back */
|
|
|
|
xfr->tsigctx = msg->tsigctx;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_message_destroy(&msg);
|
|
|
|
|
1999-12-13 03:01:53 +00:00
|
|
|
if (xfr->state == XFRST_GOTSOA) {
|
|
|
|
xfr->reqtype = dns_rdatatype_axfr;
|
|
|
|
xfr->state = XFRST_INITIALSOA;
|
|
|
|
CHECK(xfrin_send_request(xfr));
|
|
|
|
} else if (xfr->state == XFRST_END) {
|
1999-12-24 00:44:59 +00:00
|
|
|
/*
|
|
|
|
* Inform the caller we succeeded.
|
|
|
|
*/
|
2000-01-28 23:48:58 +00:00
|
|
|
if (xfr->done != NULL) {
|
1999-12-24 00:44:59 +00:00
|
|
|
(xfr->done)(xfr->zone, ISC_R_SUCCESS);
|
2000-01-28 23:48:58 +00:00
|
|
|
xfr->done = NULL;
|
|
|
|
}
|
1999-12-02 22:33:15 +00:00
|
|
|
/*
|
|
|
|
* We should have no outstanding events at this
|
|
|
|
* point, thus maybe_free() should succeed.
|
|
|
|
*/
|
2000-03-29 05:03:07 +00:00
|
|
|
xfr->shuttingdown = ISC_TRUE;
|
2000-01-28 23:48:58 +00:00
|
|
|
maybe_free(xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
} else {
|
|
|
|
/* Read the next message. */
|
|
|
|
CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
|
|
|
|
xfrin_recv_done, xfr));
|
1999-08-25 06:39:19 +00:00
|
|
|
xfr->recvs++;
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
failure:
|
1999-09-10 15:01:04 +00:00
|
|
|
if (msg != NULL) {
|
|
|
|
msg->querytsig = NULL;
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_message_destroy(&msg);
|
1999-09-10 15:01:04 +00:00
|
|
|
}
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
1999-12-13 03:01:53 +00:00
|
|
|
xfrin_fail(xfr, result, "receiving responses");
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xfrin_timeout(isc_task_t *task, isc_event_t *event) {
|
2000-04-17 19:22:44 +00:00
|
|
|
dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
|
2000-03-29 05:03:07 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
UNUSED(task);
|
2000-03-29 05:03:07 +00:00
|
|
|
|
1999-08-25 10:52:57 +00:00
|
|
|
isc_event_free(&event);
|
1999-10-29 22:42:44 +00:00
|
|
|
/* This will log "giving up: timeout". */
|
1999-08-20 05:35:16 +00:00
|
|
|
xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
|
|
|
|
}
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static void
|
|
|
|
maybe_free(dns_xfrin_ctx_t *xfr) {
|
2000-03-29 05:03:07 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
if (! xfr->shuttingdown || xfr->refcount != 0 ||
|
|
|
|
xfr->connects != 0 || xfr->sends != 0 ||
|
|
|
|
xfr->recvs != 0)
|
|
|
|
return;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-12-02 22:33:15 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
|
|
|
|
|
2000-02-25 00:52:11 +00:00
|
|
|
if (xfr->transferlist != NULL) {
|
|
|
|
LOCK(&xfr->transferlist->lock);
|
|
|
|
ISC_LIST_UNLINK(xfr->transferlist->transfers, xfr, link);
|
|
|
|
UNLOCK(&xfr->transferlist->lock);
|
|
|
|
xfr->transferlist = NULL;
|
|
|
|
}
|
|
|
|
|
1999-12-02 22:33:15 +00:00
|
|
|
if (xfr->socket != NULL)
|
|
|
|
isc_socket_detach(&xfr->socket);
|
|
|
|
|
|
|
|
if (xfr->timer != NULL)
|
|
|
|
isc_timer_detach(&xfr->timer);
|
|
|
|
|
|
|
|
if (xfr->task != NULL)
|
2000-01-28 23:48:58 +00:00
|
|
|
isc_task_detach(&xfr->task);
|
1999-12-02 22:33:15 +00:00
|
|
|
|
|
|
|
if (xfr->lasttsig != NULL) {
|
|
|
|
dns_rdata_freestruct(xfr->lasttsig);
|
|
|
|
isc_mem_put(xfr->mctx, xfr->lasttsig, sizeof(*xfr->lasttsig));
|
|
|
|
}
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_diff_clear(&xfr->diff);
|
|
|
|
|
|
|
|
if (xfr->ixfr.journal != NULL)
|
|
|
|
dns_journal_destroy(&xfr->ixfr.journal);
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-08-25 06:39:19 +00:00
|
|
|
if (xfr->axfr.add_private != NULL)
|
1999-08-20 05:35:16 +00:00
|
|
|
(void) dns_db_endload(xfr->db, &xfr->axfr.add_private);
|
|
|
|
|
|
|
|
if (xfr->tcpmsg_valid)
|
|
|
|
dns_tcpmsg_invalidate(&xfr->tcpmsg);
|
|
|
|
|
1999-08-25 06:39:19 +00:00
|
|
|
if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0)
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_free(&xfr->name, xfr->mctx);
|
1999-08-25 06:39:19 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
if (xfr->ver != NULL)
|
|
|
|
dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
|
|
|
|
|
1999-10-14 00:05:02 +00:00
|
|
|
if (xfr->db != NULL)
|
1999-10-14 01:37:00 +00:00
|
|
|
dns_db_detach(&xfr->db);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-14 00:05:02 +00:00
|
|
|
if (xfr->zone != NULL)
|
2000-02-10 01:12:15 +00:00
|
|
|
dns_zone_idetach(&xfr->zone);
|
1999-10-14 00:05:02 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
|
|
|
|
}
|
1999-10-29 22:42:44 +00:00
|
|
|
|
1999-10-30 01:08:52 +00:00
|
|
|
/*
|
|
|
|
* Log incoming zone transfer messages in a format like
|
|
|
|
* transfer of <zone> from <address>: <message>
|
|
|
|
*/
|
|
|
|
static void
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_logv(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr,
|
1999-10-30 01:08:52 +00:00
|
|
|
const char *fmt, va_list ap)
|
|
|
|
{
|
2000-04-11 19:08:32 +00:00
|
|
|
char znbuf[1024];
|
1999-10-30 01:08:52 +00:00
|
|
|
isc_buffer_t masterbuf;
|
|
|
|
char mastermem[256];
|
|
|
|
isc_result_t result;
|
|
|
|
char msgmem[2048];
|
2000-01-31 15:10:29 +00:00
|
|
|
|
2000-04-11 19:08:32 +00:00
|
|
|
dns_name_format(zonename, znbuf, sizeof(znbuf));
|
1999-10-30 01:08:52 +00:00
|
|
|
|
|
|
|
isc_buffer_init(&masterbuf, mastermem, sizeof(mastermem),
|
|
|
|
ISC_BUFFERTYPE_TEXT);
|
2000-01-28 01:12:01 +00:00
|
|
|
result = isc_sockaddr_totext(masteraddr, &masterbuf);
|
1999-10-30 01:08:52 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
strcpy(masterbuf.base, "<UNKNOWN>");
|
|
|
|
|
|
|
|
vsnprintf(msgmem, sizeof(msgmem), fmt, ap);
|
|
|
|
|
|
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_XFER_IN,
|
|
|
|
DNS_LOGMODULE_XFER_IN, level,
|
2000-04-11 19:08:32 +00:00
|
|
|
"transfer of '%s' from %s: %s", znbuf,
|
1999-10-30 01:08:52 +00:00
|
|
|
masterbuf.base, msgmem);
|
|
|
|
}
|
|
|
|
|
2000-02-15 20:05:37 +00:00
|
|
|
/* Logging function for use when a xfrin_ctx_t has not yet been created. */
|
1999-10-30 01:08:52 +00:00
|
|
|
|
|
|
|
static void
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_log1(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr,
|
1999-10-30 01:08:52 +00:00
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_logv(level, zonename, masteraddr, fmt, ap);
|
1999-10-30 01:08:52 +00:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2000-02-15 20:05:37 +00:00
|
|
|
/* Logging function for use when there is a xfrin_ctx_t. */
|
1999-10-29 22:42:44 +00:00
|
|
|
|
|
|
|
static void
|
2000-01-28 23:48:58 +00:00
|
|
|
xfrin_log(dns_xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...)
|
1999-10-29 22:42:44 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2000-01-28 01:12:01 +00:00
|
|
|
xfrin_logv(level, &xfr->name, &xfr->masteraddr, fmt, ap);
|
1999-10-29 22:42:44 +00:00
|
|
|
va_end(ap);
|
|
|
|
}
|
2000-02-25 00:52:11 +00:00
|
|
|
|
|
|
|
isc_result_t dns_xfrinlist_init(dns_xfrinlist_t *list) {
|
|
|
|
ISC_LIST_INIT(list->transfers);
|
|
|
|
return (isc_mutex_init(&list->lock));
|
|
|
|
}
|
|
|
|
|
|
|
|
void dns_xfrinlist_destroy(dns_xfrinlist_t *list) {
|
|
|
|
isc_mutex_destroy(&list->lock);
|
|
|
|
}
|