mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
Keep a queue of zones waiting for zone transfer quota so that a new
transfer can be dispatched immediately whenever quota becomes available
This commit is contained in:
4
CHANGES
4
CHANGES
@@ -1,3 +1,7 @@
|
|||||||
|
173. [func] Keep a queue of zones waiting for zone transfer
|
||||||
|
quota so that a new transfer can be dispatched
|
||||||
|
immediately whenever quota becomes available.
|
||||||
|
|
||||||
172. [bug] $TTL directive was sometimes missing from dumped
|
172. [bug] $TTL directive was sometimes missing from dumped
|
||||||
master files because totext_ctx_init() failed to
|
master files because totext_ctx_init() failed to
|
||||||
initialize ctx->current_ttl_valid.
|
initialize ctx->current_ttl_valid.
|
||||||
|
@@ -49,6 +49,7 @@
|
|||||||
#define DNS_EVENT_VIEWREQSHUTDOWN (ISC_EVENTCLASS_DNS + 22)
|
#define DNS_EVENT_VIEWREQSHUTDOWN (ISC_EVENTCLASS_DNS + 22)
|
||||||
#define DNS_EVENT_NOTIFYSENDTOADDR (ISC_EVENTCLASS_DNS + 23)
|
#define DNS_EVENT_NOTIFYSENDTOADDR (ISC_EVENTCLASS_DNS + 23)
|
||||||
#define DNS_EVENT_ZONE (ISC_EVENTCLASS_DNS + 24)
|
#define DNS_EVENT_ZONE (ISC_EVENTCLASS_DNS + 24)
|
||||||
|
#define DNS_EVENT_ZONESTARTXFRIN (ISC_EVENTCLASS_DNS + 25)
|
||||||
|
|
||||||
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
|
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
|
||||||
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)
|
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)
|
||||||
|
@@ -96,8 +96,8 @@ typedef isc_uint32_t dns_ttl_t;
|
|||||||
typedef struct dns_validator dns_validator_t;
|
typedef struct dns_validator dns_validator_t;
|
||||||
typedef struct dns_view dns_view_t;
|
typedef struct dns_view dns_view_t;
|
||||||
typedef ISC_LIST(dns_view_t) dns_viewlist_t;
|
typedef ISC_LIST(dns_view_t) dns_viewlist_t;
|
||||||
typedef struct dns_xfrinlist dns_xfrinlist_t;
|
|
||||||
typedef struct dns_zone dns_zone_t;
|
typedef struct dns_zone dns_zone_t;
|
||||||
|
typedef ISC_LIST(dns_zone_t) dns_zonelist_t;
|
||||||
typedef struct dns_zonemgr dns_zonemgr_t;
|
typedef struct dns_zonemgr dns_zonemgr_t;
|
||||||
typedef struct dns_zt dns_zt_t;
|
typedef struct dns_zt dns_zt_t;
|
||||||
|
|
||||||
|
@@ -42,12 +42,6 @@
|
|||||||
/* A transfer in progress. This is an opaque type. */
|
/* A transfer in progress. This is an opaque type. */
|
||||||
typedef struct dns_xfrin_ctx dns_xfrin_ctx_t;
|
typedef struct dns_xfrin_ctx dns_xfrin_ctx_t;
|
||||||
|
|
||||||
/* A list of transfers in progress. */
|
|
||||||
struct dns_xfrinlist {
|
|
||||||
isc_mutex_t lock;
|
|
||||||
ISC_LIST(dns_xfrin_ctx_t) transfers;
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
*** Functions
|
*** Functions
|
||||||
***/
|
***/
|
||||||
@@ -55,7 +49,8 @@ struct dns_xfrinlist {
|
|||||||
ISC_LANG_BEGINDECLS
|
ISC_LANG_BEGINDECLS
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_xfrin_create(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
|
dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
|
||||||
|
isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey,
|
||||||
isc_mem_t *mctx, isc_timermgr_t *timermgr,
|
isc_mem_t *mctx, isc_timermgr_t *timermgr,
|
||||||
isc_socketmgr_t *socketmgr, isc_task_t *task,
|
isc_socketmgr_t *socketmgr, isc_task_t *task,
|
||||||
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp);
|
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp);
|
||||||
@@ -84,10 +79,6 @@ void dns_xfrin_detach(dns_xfrin_ctx_t **xfrp);
|
|||||||
* only be one reference).
|
* only be one reference).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
isc_result_t dns_xfrinlist_init(dns_xfrinlist_t *list);
|
|
||||||
|
|
||||||
void dns_xfrinlist_destroy(dns_xfrinlist_t *list);
|
|
||||||
|
|
||||||
ISC_LANG_ENDDECLS
|
ISC_LANG_ENDDECLS
|
||||||
|
|
||||||
#endif /* DNS_XFRIN_H */
|
#endif /* DNS_XFRIN_H */
|
||||||
|
@@ -880,9 +880,6 @@ dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, int value);
|
|||||||
int
|
int
|
||||||
dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr);
|
dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr);
|
||||||
|
|
||||||
dns_xfrinlist_t *
|
|
||||||
dns_zonemgr_gettransferlist(dns_zonemgr_t *zmgr);
|
|
||||||
|
|
||||||
ISC_LANG_ENDDECLS
|
ISC_LANG_ENDDECLS
|
||||||
|
|
||||||
#endif /* DNS_ZONE_H */
|
#endif /* DNS_ZONE_H */
|
||||||
|
156
lib/dns/xfrin.c
156
lib/dns/xfrin.c
@@ -15,7 +15,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: xfrin.c,v 1.68 2000/05/10 03:33:54 tale Exp $ */
|
/* $Id: xfrin.c,v 1.69 2000/05/14 20:01:27 gson Exp $ */
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
#include <dns/journal.h>
|
#include <dns/journal.h>
|
||||||
#include <dns/log.h>
|
#include <dns/log.h>
|
||||||
#include <dns/message.h>
|
#include <dns/message.h>
|
||||||
#include <dns/peer.h>
|
|
||||||
#include <dns/rdatalist.h>
|
#include <dns/rdatalist.h>
|
||||||
#include <dns/rdataset.h>
|
#include <dns/rdataset.h>
|
||||||
#include <dns/result.h>
|
#include <dns/result.h>
|
||||||
@@ -155,9 +154,6 @@ struct dns_xfrin_ctx {
|
|||||||
dns_journal_t *journal;
|
dns_journal_t *journal;
|
||||||
|
|
||||||
} ixfr;
|
} ixfr;
|
||||||
|
|
||||||
ISC_LINK(dns_xfrin_ctx_t) link;
|
|
||||||
dns_xfrinlist_t *transferlist;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define XFRIN_MAGIC 0x58667269U /* XfrI. */
|
#define XFRIN_MAGIC 0x58667269U /* XfrI. */
|
||||||
@@ -503,132 +499,21 @@ xfr_rr(dns_xfrin_ctx_t *xfr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_xfrin_create(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
|
dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
|
||||||
|
isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey,
|
||||||
isc_mem_t *mctx, isc_timermgr_t *timermgr,
|
isc_mem_t *mctx, isc_timermgr_t *timermgr,
|
||||||
isc_socketmgr_t *socketmgr, isc_task_t *task,
|
isc_socketmgr_t *socketmgr, isc_task_t *task,
|
||||||
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
|
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
|
||||||
{
|
{
|
||||||
dns_name_t *zonename;
|
dns_name_t *zonename = dns_zone_getorigin(zone);
|
||||||
dns_xfrin_ctx_t *xfr, *x;
|
dns_xfrin_ctx_t *xfr;
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
dns_db_t *db = NULL;
|
dns_db_t *db = NULL;
|
||||||
dns_rdatatype_t xfrtype;
|
|
||||||
dns_tsigkey_t *key = NULL;
|
|
||||||
dns_name_t *keyname = NULL;
|
|
||||||
isc_netaddr_t masterip;
|
|
||||||
dns_peer_t *peer = NULL;
|
|
||||||
int maxtransfersin, maxtransfersperns;
|
|
||||||
int nxfrsin, nxfrsperns;
|
|
||||||
dns_xfrinlist_t *transferlist;
|
|
||||||
|
|
||||||
REQUIRE(xfrp != NULL && *xfrp == NULL);
|
REQUIRE(xfrp != NULL && *xfrp == NULL);
|
||||||
|
|
||||||
zonename = dns_zone_getorigin(zone);
|
(void) dns_zone_getdb(zone, &db);
|
||||||
|
|
||||||
xfrin_log1(ISC_LOG_INFO, zonename, masteraddr, "starting");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
result = dns_zone_getdb(zone, &db);
|
|
||||||
if (result == DNS_R_NOTLOADED)
|
|
||||||
INSIST(db == NULL);
|
|
||||||
else
|
|
||||||
CHECK(result);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decide whether we should request IXFR or AXFR.
|
|
||||||
*/
|
|
||||||
if (db == NULL) {
|
|
||||||
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
|
|
||||||
"no database exists yet, "
|
|
||||||
"requesting AXFR of initial version");
|
|
||||||
xfrtype = dns_rdatatype_axfr;
|
|
||||||
} else {
|
|
||||||
isc_boolean_t use_ixfr = ISC_TRUE;
|
|
||||||
if (peer != NULL &&
|
|
||||||
dns_peer_getrequestixfr(peer, &use_ixfr) ==
|
|
||||||
ISC_R_SUCCESS) {
|
|
||||||
; /* Using peer setting */
|
|
||||||
} else {
|
|
||||||
use_ixfr = dns_zone_getview(zone)->requestixfr;
|
|
||||||
}
|
|
||||||
if (use_ixfr == ISC_FALSE) {
|
|
||||||
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
|
|
||||||
"IXFR disabled, requesting AXFR");
|
|
||||||
xfrtype = dns_rdatatype_axfr;
|
|
||||||
} else {
|
|
||||||
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
|
|
||||||
"requesting IXFR");
|
|
||||||
xfrtype = dns_rdatatype_ixfr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
maxtransfersin =
|
|
||||||
dns_zonemgr_getttransfersin(dns_zone_getmgr(zone));
|
|
||||||
maxtransfersperns =
|
|
||||||
dns_zonemgr_getttransfersperns(dns_zone_getmgr(zone));
|
|
||||||
if (peer != NULL) {
|
|
||||||
(void) dns_peer_gettransfers(peer, &maxtransfersperns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
transferlist = dns_zonemgr_gettransferlist(dns_zone_getmgr(zone));
|
|
||||||
LOCK(&transferlist->lock);
|
|
||||||
nxfrsin = nxfrsperns = 0;
|
|
||||||
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);
|
|
||||||
nxfrsin++;
|
|
||||||
if (isc_netaddr_equal(&xip, &masterip))
|
|
||||||
nxfrsperns++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nxfrsin >= maxtransfersin || nxfrsperns >= maxtransfersperns) {
|
|
||||||
result = ISC_R_QUOTA;
|
|
||||||
xfrin_log1(ISC_LOG_INFO, zonename, masteraddr,
|
|
||||||
"deferred: %s", isc_result_totext(result));
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = xfrin_create(mctx,
|
result = xfrin_create(mctx,
|
||||||
zone,
|
zone,
|
||||||
db,
|
db,
|
||||||
@@ -637,15 +522,11 @@ dns_xfrin_create(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
|
|||||||
socketmgr,
|
socketmgr,
|
||||||
zonename,
|
zonename,
|
||||||
dns_zone_getclass(zone), xfrtype,
|
dns_zone_getclass(zone), xfrtype,
|
||||||
masteraddr, key, &xfr);
|
masteraddr, tsigkey, &xfr);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
xfr->transferlist = transferlist;
|
|
||||||
ISC_LIST_APPEND(transferlist->transfers, xfr, link);
|
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
UNLOCK(&transferlist->lock);
|
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
CHECK(xfrin_start(xfr));
|
CHECK(xfrin_start(xfr));
|
||||||
@@ -773,9 +654,6 @@ xfrin_create(isc_mem_t *mctx,
|
|||||||
xfr->axfr.add_func = NULL;
|
xfr->axfr.add_func = NULL;
|
||||||
xfr->axfr.add_private = NULL;
|
xfr->axfr.add_private = NULL;
|
||||||
|
|
||||||
ISC_LINK_INIT(xfr, link);
|
|
||||||
xfr->transferlist = NULL;
|
|
||||||
|
|
||||||
CHECK(dns_name_dup(zonename, mctx, &xfr->name));
|
CHECK(dns_name_dup(zonename, mctx, &xfr->name));
|
||||||
|
|
||||||
isc_interval_set(&maxinterval, dns_zone_getmaxxfrin(xfr->zone), 0);
|
isc_interval_set(&maxinterval, dns_zone_getmaxxfrin(xfr->zone), 0);
|
||||||
@@ -1267,13 +1145,6 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
|
|||||||
|
|
||||||
xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
|
xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
|
||||||
|
|
||||||
if (xfr->transferlist != NULL) {
|
|
||||||
LOCK(&xfr->transferlist->lock);
|
|
||||||
ISC_LIST_UNLINK(xfr->transferlist->transfers, xfr, link);
|
|
||||||
UNLOCK(&xfr->transferlist->lock);
|
|
||||||
xfr->transferlist = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xfr->socket != NULL)
|
if (xfr->socket != NULL)
|
||||||
isc_socket_detach(&xfr->socket);
|
isc_socket_detach(&xfr->socket);
|
||||||
|
|
||||||
@@ -1369,14 +1240,3 @@ xfrin_log(dns_xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...)
|
|||||||
xfrin_logv(level, &xfr->name, &xfr->masteraddr, fmt, ap);
|
xfrin_logv(level, &xfr->name, &xfr->masteraddr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
373
lib/dns/zone.c
373
lib/dns/zone.c
@@ -15,7 +15,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: zone.c,v 1.112 2000/05/12 10:21:06 marka Exp $ */
|
/* $Id: zone.c,v 1.113 2000/05/14 20:01:25 gson Exp $ */
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
#include <dns/log.h>
|
#include <dns/log.h>
|
||||||
#include <dns/masterdump.h>
|
#include <dns/masterdump.h>
|
||||||
#include <dns/message.h>
|
#include <dns/message.h>
|
||||||
|
#include <dns/peer.h>
|
||||||
#include <dns/rcode.h>
|
#include <dns/rcode.h>
|
||||||
#include <dns/rdatalist.h>
|
#include <dns/rdatalist.h>
|
||||||
#include <dns/rdataset.h>
|
#include <dns/rdataset.h>
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
#include <dns/resolver.h>
|
#include <dns/resolver.h>
|
||||||
#include <dns/result.h>
|
#include <dns/result.h>
|
||||||
#include <dns/ssu.h>
|
#include <dns/ssu.h>
|
||||||
|
#include <dns/tsig.h>
|
||||||
#include <dns/xfrin.h>
|
#include <dns/xfrin.h>
|
||||||
#include <dns/zone.h>
|
#include <dns/zone.h>
|
||||||
|
|
||||||
@@ -139,6 +141,16 @@ struct dns_zone {
|
|||||||
isc_event_t ctlevent;
|
isc_event_t ctlevent;
|
||||||
dns_ssutable_t *ssutable;
|
dns_ssutable_t *ssutable;
|
||||||
dns_view_t *view;
|
dns_view_t *view;
|
||||||
|
/*
|
||||||
|
* Zones in certain states such as "waiting for zone transfer"
|
||||||
|
* or "zone transfer in progress" are kept on per-state linked lists
|
||||||
|
* in the zone manager using the 'statelink' field. The 'statelist'
|
||||||
|
* field points at the list the zone is currently on. It the zone
|
||||||
|
* is not on any such list, statelist is NULL.
|
||||||
|
*/
|
||||||
|
ISC_LINK(dns_zone_t) statelink;
|
||||||
|
dns_zonelist_t *statelist;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DNS_ZONE_FLAG(z,f) (((z)->flags & (f)) != 0)
|
#define DNS_ZONE_FLAG(z,f) (((z)->flags & (f)) != 0)
|
||||||
@@ -175,12 +187,13 @@ struct dns_zonemgr {
|
|||||||
isc_rwlock_t rwlock;
|
isc_rwlock_t rwlock;
|
||||||
isc_rwlock_t conflock;
|
isc_rwlock_t conflock;
|
||||||
/* Locked by rwlock. */
|
/* Locked by rwlock. */
|
||||||
ISC_LIST(dns_zone_t) zones;
|
dns_zonelist_t zones;
|
||||||
|
dns_zonelist_t waiting_for_xfrin;
|
||||||
|
dns_zonelist_t xfrin_in_progress;
|
||||||
|
|
||||||
/* Locked by conflock. */
|
/* Locked by conflock. */
|
||||||
int transfersin;
|
int transfersin;
|
||||||
int transfersperns;
|
int transfersperns;
|
||||||
/* Contains its own lock. */
|
|
||||||
dns_xfrinlist_t transferlist;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -202,7 +215,7 @@ static void cancel_refresh(dns_zone_t *);
|
|||||||
|
|
||||||
static void zone_log(dns_zone_t *zone, const char *, int, const char *msg,
|
static void zone_log(dns_zone_t *zone, const char *, int, const char *msg,
|
||||||
...);
|
...);
|
||||||
static void dns_zone_transfer_in(dns_zone_t *zone);
|
static void queue_xfrin(dns_zone_t *zone);
|
||||||
static isc_result_t dns_zone_tostr(dns_zone_t *zone, isc_mem_t *mctx,
|
static isc_result_t dns_zone_tostr(dns_zone_t *zone, isc_mem_t *mctx,
|
||||||
char **s);
|
char **s);
|
||||||
static void zone_unload(dns_zone_t *zone);
|
static void zone_unload(dns_zone_t *zone);
|
||||||
@@ -231,7 +244,10 @@ static isc_result_t notify_createmessage(dns_zone_t *zone,
|
|||||||
static void notify_done(isc_task_t *task, isc_event_t *event);
|
static void notify_done(isc_task_t *task, isc_event_t *event);
|
||||||
static void notify_send_toaddr(isc_task_t *task, isc_event_t *event);
|
static void notify_send_toaddr(isc_task_t *task, isc_event_t *event);
|
||||||
static isc_result_t zone_dump(dns_zone_t *);
|
static isc_result_t zone_dump(dns_zone_t *);
|
||||||
|
static void got_transfer_quota(isc_task_t *task, isc_event_t *event);
|
||||||
|
static isc_result_t zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone);
|
||||||
|
static void zmgr_resume_xfrs(dns_zonemgr_t *zmgr);
|
||||||
|
|
||||||
#define PRINT_ZONE_REF(zone) \
|
#define PRINT_ZONE_REF(zone) \
|
||||||
do { \
|
do { \
|
||||||
char *s = NULL; \
|
char *s = NULL; \
|
||||||
@@ -331,6 +347,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
|
|||||||
zone->diff_on_reload = ISC_FALSE;
|
zone->diff_on_reload = ISC_FALSE;
|
||||||
zone->ssutable = NULL;
|
zone->ssutable = NULL;
|
||||||
zone->view = NULL;
|
zone->view = NULL;
|
||||||
|
ISC_LINK_INIT(zone, statelink);
|
||||||
|
zone->statelist = NULL;
|
||||||
|
|
||||||
zone->magic = ZONE_MAGIC;
|
zone->magic = ZONE_MAGIC;
|
||||||
ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL,
|
ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL,
|
||||||
DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone,
|
DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone,
|
||||||
@@ -349,7 +368,6 @@ zone_free(dns_zone_t *zone) {
|
|||||||
zone->flags |= DNS_ZONE_F_EXITING;
|
zone->flags |= DNS_ZONE_F_EXITING;
|
||||||
UNLOCK(&zone->lock);
|
UNLOCK(&zone->lock);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Managed objects. Order is important.
|
* Managed objects. Order is important.
|
||||||
*/
|
*/
|
||||||
@@ -365,8 +383,10 @@ zone_free(dns_zone_t *zone) {
|
|||||||
isc_task_detach(&zone->task);
|
isc_task_detach(&zone->task);
|
||||||
if (zone->zmgr)
|
if (zone->zmgr)
|
||||||
dns_zonemgr_releasezone(zone->zmgr, zone);
|
dns_zonemgr_releasezone(zone->zmgr, zone);
|
||||||
|
|
||||||
|
INSIST(zone->statelist == NULL);
|
||||||
|
|
||||||
/* unmanaged objects */
|
/* Unmanaged objects */
|
||||||
if (zone->dbname != NULL)
|
if (zone->dbname != NULL)
|
||||||
isc_mem_free(zone->mctx, zone->dbname);
|
isc_mem_free(zone->mctx, zone->dbname);
|
||||||
zone->dbname = NULL;
|
zone->dbname = NULL;
|
||||||
@@ -1635,9 +1655,9 @@ notify_send_queue(notify_t *notify) {
|
|||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
|
|
||||||
e = isc_event_allocate(notify->mctx, NULL,
|
e = isc_event_allocate(notify->mctx, NULL,
|
||||||
DNS_EVENT_NOTIFYSENDTOADDR,
|
DNS_EVENT_NOTIFYSENDTOADDR,
|
||||||
notify_send_toaddr,
|
notify_send_toaddr,
|
||||||
notify, sizeof(isc_event_t));
|
notify, sizeof(isc_event_t));
|
||||||
if (e == NULL)
|
if (e == NULL)
|
||||||
return (ISC_R_NOMEMORY);
|
return (ISC_R_NOMEMORY);
|
||||||
e->ev_arg = notify;
|
e->ev_arg = notify;
|
||||||
@@ -1885,7 +1905,7 @@ dns_zone_notify(dns_zone_t *zone) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
refresh_callback(isc_task_t *task, isc_event_t *event) {
|
refresh_callback(isc_task_t *task, isc_event_t *event) {
|
||||||
char me[] = "refresh_callback";
|
const char me[] = "refresh_callback";
|
||||||
dns_requestevent_t *revent = (dns_requestevent_t *)event;
|
dns_requestevent_t *revent = (dns_requestevent_t *)event;
|
||||||
dns_zone_t *zone;
|
dns_zone_t *zone;
|
||||||
dns_message_t *msg = NULL;
|
dns_message_t *msg = NULL;
|
||||||
@@ -2045,7 +2065,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
|
|||||||
tcp_transfer:
|
tcp_transfer:
|
||||||
isc_event_free(&event);
|
isc_event_free(&event);
|
||||||
dns_request_destroy(&zone->request);
|
dns_request_destroy(&zone->request);
|
||||||
dns_zone_transfer_in(zone);
|
queue_xfrin(zone);
|
||||||
} else if (isc_serial_eq(soa.serial, zone->serial)) {
|
} else if (isc_serial_eq(soa.serial, zone->serial)) {
|
||||||
dns_zone_uptodate(zone);
|
dns_zone_uptodate(zone);
|
||||||
goto next_master;
|
goto next_master;
|
||||||
@@ -2212,6 +2232,19 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
|
|||||||
LOCK(&zone->lock);
|
LOCK(&zone->lock);
|
||||||
zone->flags |= DNS_ZONE_F_EXITING;
|
zone->flags |= DNS_ZONE_F_EXITING;
|
||||||
UNLOCK(&zone->lock);
|
UNLOCK(&zone->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we were waiting for xfrin quota, step out of
|
||||||
|
* the queue.
|
||||||
|
*/
|
||||||
|
if (zone->statelist == &zone->zmgr->waiting_for_xfrin) {
|
||||||
|
RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
|
||||||
|
ISC_LIST_UNLINK(zone->zmgr->waiting_for_xfrin, zone,
|
||||||
|
statelink);
|
||||||
|
RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
|
||||||
|
zone->statelist = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (zone->xfr != NULL)
|
if (zone->xfr != NULL)
|
||||||
dns_xfrin_shutdown(zone->xfr);
|
dns_xfrin_shutdown(zone->xfr);
|
||||||
|
|
||||||
@@ -2720,8 +2753,7 @@ dns_zone_getjournalsize(dns_zone_t *zone) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
zone_log(dns_zone_t *zone, const char *me, int level,
|
zone_log(dns_zone_t *zone, const char *me, int level, const char *fmt, ...) {
|
||||||
const char *fmt, ...) {
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char message[4096];
|
char message[4096];
|
||||||
char namebuf[1024+32];
|
char namebuf[1024+32];
|
||||||
@@ -2881,7 +2913,7 @@ record_serial() {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
notify_done(isc_task_t *task, isc_event_t *event) {
|
notify_done(isc_task_t *task, isc_event_t *event) {
|
||||||
char me[] = "notify_done";
|
const char me[] = "notify_done";
|
||||||
notify_t *notify;
|
notify_t *notify;
|
||||||
dns_zone_t *zone = NULL;
|
dns_zone_t *zone = NULL;
|
||||||
|
|
||||||
@@ -3112,6 +3144,16 @@ xfrdone(dns_zone_t *zone, isc_result_t result) {
|
|||||||
if (zone->xfr != NULL)
|
if (zone->xfr != NULL)
|
||||||
dns_xfrin_detach(&zone->xfr);
|
dns_xfrin_detach(&zone->xfr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This transfer finishing freed up a transfer quota slot.
|
||||||
|
* Let any zones waiting for quota have it.
|
||||||
|
*/
|
||||||
|
RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
|
||||||
|
ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink);
|
||||||
|
zone->statelist = NULL;
|
||||||
|
zmgr_resume_xfrs(zone->zmgr);
|
||||||
|
RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retry with a different server if necessary.
|
* Retry with a different server if necessary.
|
||||||
*/
|
*/
|
||||||
@@ -3134,28 +3176,152 @@ dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table) {
|
|||||||
zone->ssutable = table;
|
zone->ssutable = table;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
*** Zone manager.
|
|
||||||
***/
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dns_zone_transfer_in(dns_zone_t *zone) {
|
queue_xfrin(dns_zone_t *zone) {
|
||||||
const char me[] = "dns_zone_transfer_in";
|
const char me[] = "queue_xfrin";
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
|
dns_zonemgr_t *zmgr = zone->zmgr;
|
||||||
|
|
||||||
DNS_ENTER;
|
DNS_ENTER;
|
||||||
|
|
||||||
if (zone->masterscnt < 1)
|
INSIST(zone->statelist == NULL);
|
||||||
return;
|
|
||||||
|
|
||||||
result = dns_xfrin_create(zone, &zone->masteraddr, zone->mctx,
|
RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
|
||||||
|
ISC_LIST_APPEND(zmgr->waiting_for_xfrin, zone, statelink);
|
||||||
|
zone->statelist = &zmgr->waiting_for_xfrin;
|
||||||
|
result = zmgr_start_xfrin_ifquota(zmgr, zone);
|
||||||
|
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
|
||||||
|
|
||||||
|
if (result == ISC_R_QUOTA) {
|
||||||
|
zone_log(zone, me, ISC_LOG_DEBUG(1),
|
||||||
|
"zone transfer deferred due to quota");
|
||||||
|
} else if (result != ISC_R_SUCCESS) {
|
||||||
|
zone_log(zone, me, ISC_LOG_ERROR,
|
||||||
|
"starting zone transfer: %s",
|
||||||
|
isc_result_totext(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format a human-readable representation of the socket address '*sa'
|
||||||
|
* into the character array 'array', which is of size 'size'.
|
||||||
|
* The resulting string is guaranteed to be null-terminated.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size)
|
||||||
|
{
|
||||||
|
isc_result_t result;
|
||||||
|
isc_buffer_t buf;
|
||||||
|
|
||||||
|
isc_buffer_init(&buf, array, size);
|
||||||
|
result = isc_sockaddr_totext(sa, &buf);
|
||||||
|
if (result != ISC_R_SUCCESS) {
|
||||||
|
snprintf(array, size,
|
||||||
|
"<unknown address, family %u>",
|
||||||
|
sa->type.sa.sa_family);
|
||||||
|
array[size - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This event callback is called when a zone has received
|
||||||
|
* any necessary zone transfer quota. This is the time
|
||||||
|
* to go ahead and start the transfer.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
got_transfer_quota(isc_task_t *task, isc_event_t *event) {
|
||||||
|
const char me[] = "got_transfer_quota";
|
||||||
|
isc_result_t result;
|
||||||
|
dns_peer_t *peer = NULL;
|
||||||
|
dns_tsigkey_t *tsigkey = NULL;
|
||||||
|
dns_name_t *keyname = NULL;
|
||||||
|
char mastertext[256];
|
||||||
|
dns_rdatatype_t xfrtype;
|
||||||
|
dns_zone_t *zone = event->ev_arg;
|
||||||
|
isc_netaddr_t masterip;
|
||||||
|
|
||||||
|
UNUSED(task);
|
||||||
|
|
||||||
|
INSIST(task == zone->task);
|
||||||
|
|
||||||
|
if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING)) {
|
||||||
|
result = ISC_R_CANCELED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_format(&zone->masteraddr, mastertext, sizeof(mastertext));
|
||||||
|
|
||||||
|
isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
|
||||||
|
(void)dns_peerlist_peerbyaddr(zone->view->peers,
|
||||||
|
&masterip, &peer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decide whether we should request IXFR or AXFR.
|
||||||
|
*/
|
||||||
|
if (zone->db == NULL) {
|
||||||
|
zone_log(zone, me, ISC_LOG_DEBUG(3),
|
||||||
|
"no database exists yet, requesting AXFR of "
|
||||||
|
"initial version from %s", mastertext);
|
||||||
|
xfrtype = dns_rdatatype_axfr;
|
||||||
|
} else {
|
||||||
|
isc_boolean_t use_ixfr = ISC_TRUE;
|
||||||
|
if (peer != NULL &&
|
||||||
|
dns_peer_getrequestixfr(peer, &use_ixfr) ==
|
||||||
|
ISC_R_SUCCESS) {
|
||||||
|
; /* Using peer setting */
|
||||||
|
} else {
|
||||||
|
use_ixfr = zone->view->requestixfr;
|
||||||
|
}
|
||||||
|
if (use_ixfr == ISC_FALSE) {
|
||||||
|
zone_log(zone, me, ISC_LOG_DEBUG(3),
|
||||||
|
"IXFR disabled, requesting AXFR from %s",
|
||||||
|
mastertext);
|
||||||
|
xfrtype = dns_rdatatype_axfr;
|
||||||
|
} else {
|
||||||
|
zone_log(zone, me, ISC_LOG_DEBUG(3),
|
||||||
|
"requesting IXFR form %s",
|
||||||
|
mastertext);
|
||||||
|
xfrtype = dns_rdatatype_ixfr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(&tsigkey, keyname, NULL,
|
||||||
|
view->statickeys);
|
||||||
|
if (result == ISC_R_NOTFOUND)
|
||||||
|
result = dns_tsigkey_find(&tsigkey, keyname, NULL,
|
||||||
|
view->dynamickeys);
|
||||||
|
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
|
||||||
|
zone_log(zone, me, ISC_LOG_ERROR,
|
||||||
|
"error getting tsig keys for zone transfer: %s",
|
||||||
|
isc_result_totext(result));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = dns_xfrin_create(zone, xfrtype, &zone->masteraddr,
|
||||||
|
tsigkey, zone->mctx,
|
||||||
zone->zmgr->timermgr, zone->zmgr->socketmgr,
|
zone->zmgr->timermgr, zone->zmgr->socketmgr,
|
||||||
zone->task,
|
zone->task, xfrdone, &zone->xfr);
|
||||||
xfrdone, &zone->xfr);
|
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
xfrdone(zone, result);
|
xfrdone(zone, result);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
isc_event_free(&event);
|
||||||
|
|
||||||
|
dns_zone_detach(&zone);
|
||||||
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*** Zone manager.
|
||||||
|
***/
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||||
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
|
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
|
||||||
@@ -3177,6 +3343,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||||||
zmgr->task = NULL;
|
zmgr->task = NULL;
|
||||||
zmgr->rl = NULL;
|
zmgr->rl = NULL;
|
||||||
ISC_LIST_INIT(zmgr->zones);
|
ISC_LIST_INIT(zmgr->zones);
|
||||||
|
ISC_LIST_INIT(zmgr->waiting_for_xfrin);
|
||||||
|
ISC_LIST_INIT(zmgr->xfrin_in_progress);
|
||||||
result = isc_rwlock_init(&zmgr->rwlock, 0, 0);
|
result = isc_rwlock_init(&zmgr->rwlock, 0, 0);
|
||||||
if (result != ISC_R_SUCCESS) {
|
if (result != ISC_R_SUCCESS) {
|
||||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||||
@@ -3197,20 +3365,11 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||||||
zmgr->transfersin = 10;
|
zmgr->transfersin = 10;
|
||||||
zmgr->transfersperns = 2;
|
zmgr->transfersperns = 2;
|
||||||
|
|
||||||
result = dns_xfrinlist_init(&zmgr->transferlist);
|
|
||||||
if (result != ISC_R_SUCCESS) {
|
|
||||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
|
||||||
"dns_transferlist_init() failed: %s",
|
|
||||||
isc_result_totext(result));
|
|
||||||
result = ISC_R_UNEXPECTED;
|
|
||||||
goto free_conflock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the zone task pool. */
|
/* Create the zone task pool. */
|
||||||
result = isc_taskpool_create(taskmgr, mctx,
|
result = isc_taskpool_create(taskmgr, mctx,
|
||||||
8 /* XXX */, 0, &zmgr->zonetasks);
|
8 /* XXX */, 0, &zmgr->zonetasks);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
goto free_transferlist;
|
goto free_conflock;
|
||||||
|
|
||||||
/* Create a single task for queueing of SOA queries. */
|
/* Create a single task for queueing of SOA queries. */
|
||||||
result = isc_task_create(taskmgr, 1, &zmgr->task);
|
result = isc_task_create(taskmgr, 1, &zmgr->task);
|
||||||
@@ -3232,8 +3391,6 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||||||
|
|
||||||
free_task:
|
free_task:
|
||||||
isc_task_detach(&zmgr->task);
|
isc_task_detach(&zmgr->task);
|
||||||
free_transferlist:
|
|
||||||
dns_xfrinlist_destroy(&zmgr->transferlist);
|
|
||||||
free_taskpool:
|
free_taskpool:
|
||||||
isc_taskpool_destroy(&zmgr->zonetasks);
|
isc_taskpool_destroy(&zmgr->zonetasks);
|
||||||
free_conflock:
|
free_conflock:
|
||||||
@@ -3386,13 +3543,143 @@ dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr) {
|
|||||||
return (zmgr->transfersperns);
|
return (zmgr->transfersperns);
|
||||||
}
|
}
|
||||||
|
|
||||||
dns_xfrinlist_t *
|
/*
|
||||||
dns_zonemgr_gettransferlist(dns_zonemgr_t *zmgr) {
|
* Try to start a new incoming zone transfer to fill a quota
|
||||||
return (&zmgr->transferlist);
|
* slot that was just vacated.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* The zone manager is locked by the caller.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
zmgr_resume_xfrs(dns_zonemgr_t *zmgr) {
|
||||||
|
static char me[] = "zmgr_resume_xfrs";
|
||||||
|
dns_zone_t *zone;
|
||||||
|
|
||||||
|
for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin);
|
||||||
|
zone != NULL;
|
||||||
|
zone = ISC_LIST_NEXT(zone, statelink))
|
||||||
|
{
|
||||||
|
isc_result_t result;
|
||||||
|
result = zmgr_start_xfrin_ifquota(zmgr, zone);
|
||||||
|
if (result == ISC_R_SUCCESS) {
|
||||||
|
/*
|
||||||
|
* We successfully filled the slot. We're done.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
} else if (result == ISC_R_QUOTA) {
|
||||||
|
/*
|
||||||
|
* Not enough quota. This is probably the per-server
|
||||||
|
* quota, because we only get called when a unit of
|
||||||
|
* global quota has just been freed. Try the next
|
||||||
|
* zone, it may succeed if it uses another master.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
zone_log(zone, me, ISC_LOG_DEBUG(3),
|
||||||
|
"starting zone transfer: %s",
|
||||||
|
isc_result_totext(result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to start an incoming zone transfer for 'zone', quota permitting.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* The zone manager is locked by the caller.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* ISC_R_SUCCESS There was enough quota and we attempted to
|
||||||
|
* start a transfer. xfrdone() has been or will
|
||||||
|
* be called.
|
||||||
|
* ISC_R_QUOTA Not enough quota.
|
||||||
|
* Others Failure.
|
||||||
|
*/
|
||||||
|
static isc_result_t
|
||||||
|
zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
|
||||||
|
dns_peer_t *peer = NULL;
|
||||||
|
isc_netaddr_t masterip;
|
||||||
|
int nxfrsin, nxfrsperns;
|
||||||
|
dns_zone_t *x;
|
||||||
|
int maxtransfersin, maxtransfersperns;
|
||||||
|
isc_event_t *e;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find any configured information about the server we'd
|
||||||
|
* like to transfer this zone from.
|
||||||
|
*/
|
||||||
|
isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
|
||||||
|
(void)dns_peerlist_peerbyaddr(zone->view->peers,
|
||||||
|
&masterip, &peer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the total maximum number of simultaneous
|
||||||
|
* transfers allowed, and the maximum for this specific
|
||||||
|
* master.
|
||||||
|
*/
|
||||||
|
maxtransfersin = zmgr->transfersin;
|
||||||
|
maxtransfersperns = zmgr->transfersperns;
|
||||||
|
if (peer != NULL)
|
||||||
|
(void)dns_peer_gettransfers(peer, &maxtransfersperns);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count the total number of transfers that are in progress,
|
||||||
|
* and the number of transfers 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.
|
||||||
|
*/
|
||||||
|
nxfrsin = nxfrsperns = 0;
|
||||||
|
for (x = ISC_LIST_HEAD(zmgr->xfrin_in_progress);
|
||||||
|
x != NULL;
|
||||||
|
x = ISC_LIST_NEXT(x, statelink))
|
||||||
|
{
|
||||||
|
isc_netaddr_t xip;
|
||||||
|
isc_netaddr_fromsockaddr(&xip, &x->masteraddr);
|
||||||
|
nxfrsin++;
|
||||||
|
if (isc_netaddr_equal(&xip, &masterip))
|
||||||
|
nxfrsperns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enforce quota. */
|
||||||
|
if (nxfrsin >= maxtransfersin)
|
||||||
|
return (ISC_R_QUOTA);
|
||||||
|
|
||||||
|
if (nxfrsperns >= maxtransfersperns)
|
||||||
|
return (ISC_R_QUOTA);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have sufficient quota. Move the zone to the "xfrin_in_progress"
|
||||||
|
* list and send it an event to let it start the actual transfer in the
|
||||||
|
* context of its own task.
|
||||||
|
*/
|
||||||
|
e = isc_event_allocate(zmgr->mctx, zmgr,
|
||||||
|
DNS_EVENT_ZONESTARTXFRIN,
|
||||||
|
got_transfer_quota, zone,
|
||||||
|
sizeof(isc_event_t));
|
||||||
|
if (e == NULL)
|
||||||
|
return (ISC_R_NOMEMORY);
|
||||||
|
|
||||||
|
LOCK(&zone->lock);
|
||||||
|
INSIST(zone->statelist == &zmgr->waiting_for_xfrin);
|
||||||
|
ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink);
|
||||||
|
ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink);
|
||||||
|
zone->statelist = &zmgr->xfrin_in_progress;
|
||||||
|
isc_task_send(zone->task, &e);
|
||||||
|
/*
|
||||||
|
* Make sure the zone does not go away before it has processed
|
||||||
|
* the event; in effect, the event is attached to the zone.
|
||||||
|
* We must use erefs rather than irefs because accesses
|
||||||
|
* to irefs are not locked.
|
||||||
|
*/
|
||||||
|
zone->erefs++;
|
||||||
|
UNLOCK(&zone->lock);
|
||||||
|
|
||||||
|
return (ISC_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* hook for ondestroy notifcation from a database. */
|
/* Hook for ondestroy notifcation from a database. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) {
|
dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) {
|
||||||
|
Reference in New Issue
Block a user