mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-31 14:25:41 +00:00
Merge changes between 3.0rc7 and 3.0rc8pl2.
This commit is contained in:
444
server/ddns.c
444
server/ddns.c
@@ -43,7 +43,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: ddns.c,v 1.15 2001/03/16 00:23:59 mellon Exp $ Copyright (c) 2000-2001 The Internet Software Consortium. All rights reserved.\n";
|
||||
"$Id: ddns.c,v 1.16 2001/06/27 00:31:05 mellon Exp $ Copyright (c) 2000-2001 The Internet Software Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@@ -52,9 +52,6 @@ static char copyright[] =
|
||||
|
||||
#ifdef NSUPDATE
|
||||
|
||||
/* Have to use TXT records for now. */
|
||||
#define T_DHCID T_TXT
|
||||
|
||||
/* DN: No way of checking that there is enough space in a data_string's
|
||||
buffer. Be certain to allocate enough!
|
||||
TL: This is why the expression evaluation code allocates a *new*
|
||||
@@ -68,232 +65,6 @@ static void data_string_append (struct data_string *ds1,
|
||||
ds1 -> len += ds2 -> len;
|
||||
}
|
||||
|
||||
static isc_result_t ddns_update_a (struct data_string *ddns_fwd_name,
|
||||
struct iaddr ddns_addr,
|
||||
struct data_string *ddns_dhcid,
|
||||
unsigned long ttl)
|
||||
{
|
||||
ns_updque updqueue;
|
||||
ns_updrec *updrec;
|
||||
isc_result_t result;
|
||||
char ddns_address [16];
|
||||
|
||||
if (ddns_addr.len != 4)
|
||||
return ISC_R_INVALIDARG;
|
||||
#ifndef NO_SNPRINTF
|
||||
snprintf (ddns_address, 16, "%d.%d.%d.%d",
|
||||
ddns_addr.iabuf[0], ddns_addr.iabuf[1],
|
||||
ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
|
||||
#else
|
||||
sprintf (ddns_address, "%d.%d.%d.%d",
|
||||
ddns_addr.iabuf[0], ddns_addr.iabuf[1],
|
||||
ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When a DHCP client or server intends to update an A RR, it first
|
||||
* prepares a DNS UPDATE query which includes as a prerequisite the
|
||||
* assertion that the name does not exist. The update section of the
|
||||
* query attempts to add the new name and its IP address mapping (an A
|
||||
* RR), and the DHCID RR with its unique client-identity.
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
ISC_LIST_INIT (updqueue);
|
||||
|
||||
/*
|
||||
* A RR does not exist.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_PREREQ,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)0;
|
||||
updrec -> r_size = 0;
|
||||
updrec -> r_opcode = NXDOMAIN;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Add A RR.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_UPDATE,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, ttl);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)ddns_address;
|
||||
updrec -> r_size = strlen (ddns_address);
|
||||
updrec -> r_opcode = ADD;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Add DHCID RR.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_UPDATE,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_DHCID, ttl);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = ddns_dhcid -> data;
|
||||
updrec -> r_size = ddns_dhcid -> len;
|
||||
updrec -> r_opcode = ADD;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Attempt to perform the update.
|
||||
*/
|
||||
result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
|
||||
|
||||
print_dns_status ((int)result, &updqueue);
|
||||
|
||||
while (!ISC_LIST_EMPTY (updqueue)) {
|
||||
updrec = ISC_LIST_HEAD (updqueue);
|
||||
ISC_LIST_UNLINK (updqueue, updrec, r_link);
|
||||
minires_freeupdrec (updrec);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If this update operation succeeds, the updater can conclude that it
|
||||
* has added a new name whose only RRs are the A and DHCID RR records.
|
||||
* The A RR update is now complete (and a client updater is finished,
|
||||
* while a server might proceed to perform a PTR RR update).
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
return result;
|
||||
|
||||
|
||||
/*
|
||||
* If the first update operation fails with YXDOMAIN, the updater can
|
||||
* conclude that the intended name is in use. The updater then
|
||||
* attempts to confirm that the DNS name is not being used by some
|
||||
* other host. The updater prepares a second UPDATE query in which the
|
||||
* prerequisite is that the desired name has attached to it a DHCID RR
|
||||
* whose contents match the client identity. The update section of
|
||||
* this query deletes the existing A records on the name, and adds the
|
||||
* A record that matches the DHCP binding and the DHCID RR with the
|
||||
* client identity.
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
if (result != ISC_R_YXDOMAIN)
|
||||
return result;
|
||||
|
||||
|
||||
/*
|
||||
* DHCID RR exists, and matches client identity.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_PREREQ,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_DHCID, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = ddns_dhcid -> data;
|
||||
updrec -> r_size = ddns_dhcid -> len;
|
||||
updrec -> r_opcode = YXRRSET;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Delete A RRset.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_UPDATE,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)0;
|
||||
updrec -> r_size = 0;
|
||||
updrec -> r_opcode = DELETE;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Add A RR.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_UPDATE,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, ttl);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)ddns_address;
|
||||
updrec -> r_size = strlen (ddns_address);
|
||||
updrec -> r_opcode = ADD;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Attempt to perform the update.
|
||||
*/
|
||||
result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
|
||||
|
||||
print_dns_status ((int)result, &updqueue);
|
||||
|
||||
/*
|
||||
* If this query succeeds, the updater can conclude that the current
|
||||
* client was the last client associated with the domain name, and that
|
||||
* the name now contains the updated A RR. The A RR update is now
|
||||
* complete (and a client updater is finished, while a server would
|
||||
* then proceed to perform a PTR RR update).
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
/*
|
||||
* If the second query fails with NXRRSET, the updater must conclude
|
||||
* that the client's desired name is in use by another host. At this
|
||||
* juncture, the updater can decide (based on some administrative
|
||||
* configuration outside of the scope of this document) whether to let
|
||||
* the existing owner of the name keep that name, and to (possibly)
|
||||
* perform some name disambiguation operation on behalf of the current
|
||||
* client, or to replace the RRs on the name with RRs that represent
|
||||
* the current client. If the configured policy allows replacement of
|
||||
* existing records, the updater submits a query that deletes the
|
||||
* existing A RR and the existing DHCID RR, adding A and DHCID RRs that
|
||||
* represent the IP address and client-identity of the new client.
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
error:
|
||||
while (!ISC_LIST_EMPTY (updqueue)) {
|
||||
updrec = ISC_LIST_HEAD (updqueue);
|
||||
ISC_LIST_UNLINK (updqueue, updrec, r_link);
|
||||
minires_freeupdrec (updrec);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static isc_result_t ddns_update_ptr (struct data_string *ddns_fwd_name,
|
||||
struct data_string *ddns_rev_name,
|
||||
unsigned long ttl)
|
||||
@@ -365,186 +136,6 @@ static isc_result_t ddns_update_ptr (struct data_string *ddns_fwd_name,
|
||||
}
|
||||
|
||||
|
||||
static isc_result_t ddns_remove_a (struct data_string *ddns_fwd_name,
|
||||
struct iaddr ddns_addr,
|
||||
struct data_string *ddns_dhcid)
|
||||
{
|
||||
ns_updque updqueue;
|
||||
ns_updrec *updrec;
|
||||
isc_result_t result = SERVFAIL;
|
||||
char ddns_address [16];
|
||||
|
||||
if (ddns_addr.len != 4)
|
||||
return ISC_R_INVALIDARG;
|
||||
|
||||
#ifndef NO_SNPRINTF
|
||||
snprintf (ddns_address, 16, "%d.%d.%d.%d",
|
||||
ddns_addr.iabuf[0], ddns_addr.iabuf[1],
|
||||
ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
|
||||
#else
|
||||
sprintf (ddns_address, "%d.%d.%d.%d",
|
||||
ddns_addr.iabuf[0], ddns_addr.iabuf[1],
|
||||
ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The entity chosen to handle the A record for this client (either the
|
||||
* client or the server) SHOULD delete the A record that was added when
|
||||
* the lease was made to the client.
|
||||
*
|
||||
* In order to perform this delete, the updater prepares an UPDATE
|
||||
* query which contains two prerequisites. The first prerequisite
|
||||
* asserts that the DHCID RR exists whose data is the client identity
|
||||
* described in Section 4.3. The second prerequisite asserts that the
|
||||
* data in the A RR contains the IP address of the lease that has
|
||||
* expired or been released.
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
ISC_LIST_INIT (updqueue);
|
||||
|
||||
/*
|
||||
* DHCID RR exists, and matches client identity.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_PREREQ,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_DHCID,0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = ddns_dhcid -> data;
|
||||
updrec -> r_size = ddns_dhcid -> len;
|
||||
updrec -> r_opcode = YXRRSET;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* A RR matches the expiring lease.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_PREREQ,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)ddns_address;
|
||||
updrec -> r_size = strlen (ddns_address);
|
||||
updrec -> r_opcode = YXRRSET;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
|
||||
/*
|
||||
* Delete appropriate A RR.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_UPDATE,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)ddns_address;
|
||||
updrec -> r_size = strlen (ddns_address);
|
||||
updrec -> r_opcode = DELETE;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
/*
|
||||
* Attempt to perform the update.
|
||||
*/
|
||||
result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
|
||||
print_dns_status ((int)result, &updqueue);
|
||||
|
||||
/*
|
||||
* If the query fails, the updater MUST NOT delete the DNS name. It
|
||||
* may be that the host whose lease on the server has expired has moved
|
||||
* to another network and obtained a lease from a different server,
|
||||
* which has caused the client's A RR to be replaced. It may also be
|
||||
* that some other client has been configured with a name that matches
|
||||
* the name of the DHCP client, and the policy was that the last client
|
||||
* to specify the name would get the name. In this case, the DHCID RR
|
||||
* will no longer match the updater's notion of the client-identity of
|
||||
* the host pointed to by the DNS name.
|
||||
* -- "Interaction between DHCP and DNS"
|
||||
*/
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto error;
|
||||
|
||||
while (!ISC_LIST_EMPTY (updqueue)) {
|
||||
updrec = ISC_LIST_HEAD (updqueue);
|
||||
ISC_LIST_UNLINK (updqueue, updrec, r_link);
|
||||
minires_freeupdrec (updrec);
|
||||
}
|
||||
|
||||
/* If the deletion of the A succeeded, and there are no A records
|
||||
left for this domain, then we can blow away the DHCID record
|
||||
as well. We can't blow away the DHCID record above because
|
||||
it's possible that more than one A has been added to this
|
||||
domain name. */
|
||||
ISC_LIST_INIT (updqueue);
|
||||
|
||||
/*
|
||||
* A RR does not exist.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_PREREQ,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_A, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = (unsigned char *)0;
|
||||
updrec -> r_size = 0;
|
||||
updrec -> r_opcode = NXRRSET;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
/*
|
||||
* Delete appropriate DHCID RR.
|
||||
*/
|
||||
updrec = minires_mkupdrec (S_UPDATE,
|
||||
(const char *)ddns_fwd_name -> data,
|
||||
C_IN, T_DHCID, 0);
|
||||
if (!updrec) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
updrec -> r_data = ddns_dhcid -> data;
|
||||
updrec -> r_size = ddns_dhcid -> len;
|
||||
updrec -> r_opcode = DELETE;
|
||||
|
||||
ISC_LIST_APPEND (updqueue, updrec, r_link);
|
||||
|
||||
/*
|
||||
* Attempt to perform the update.
|
||||
*/
|
||||
result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
|
||||
print_dns_status ((int)result, &updqueue);
|
||||
|
||||
/* Fall through. */
|
||||
error:
|
||||
|
||||
while (!ISC_LIST_EMPTY (updqueue)) {
|
||||
updrec = ISC_LIST_HEAD (updqueue);
|
||||
ISC_LIST_UNLINK (updqueue, updrec, r_link);
|
||||
minires_freeupdrec (updrec);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static isc_result_t ddns_remove_ptr (struct data_string *ddns_rev_name)
|
||||
{
|
||||
ns_updque updqueue;
|
||||
@@ -675,7 +266,7 @@ int ddns_updates (struct packet *packet,
|
||||
specifically configured to do so. If the client asked to do its
|
||||
own update and we allowed that, we don't do this test. */
|
||||
if (lease -> flags & STATIC_LEASE) {
|
||||
if (!(oc = lookup_option (&fqdn_universe, packet -> options,
|
||||
if (!(oc = lookup_option (&server_universe, packet -> options,
|
||||
SV_UPDATE_STATIC_LEASES)) ||
|
||||
!evaluate_boolean_option_cache (&ignorep, packet, lease,
|
||||
(struct client_state *)0,
|
||||
@@ -799,6 +390,11 @@ int ddns_updates (struct packet *packet,
|
||||
}
|
||||
in:
|
||||
|
||||
/* If we don't have a name that the client has been assigned, we
|
||||
can just skip all this. */
|
||||
if (!ddns_fwd_name.len)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Compute the RR TTL.
|
||||
*/
|
||||
@@ -867,7 +463,16 @@ int ddns_updates (struct packet *packet,
|
||||
*/
|
||||
if (server_updates_a) {
|
||||
memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
|
||||
get_dhcid (&ddns_dhcid, lease);
|
||||
if (lease -> uid && lease -> uid_len)
|
||||
result = get_dhcid (&ddns_dhcid,
|
||||
DHO_DHCP_CLIENT_IDENTIFIER,
|
||||
lease -> uid, lease -> uid_len);
|
||||
else
|
||||
result = get_dhcid (&ddns_dhcid, 0,
|
||||
lease -> hardware_addr.hbuf,
|
||||
lease -> hardware_addr.hlen);
|
||||
if (!result)
|
||||
goto badfqdn;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -885,7 +490,7 @@ int ddns_updates (struct packet *packet,
|
||||
*/
|
||||
if (ddns_fwd_name.len && ddns_dhcid.len)
|
||||
rcode1 = ddns_update_a (&ddns_fwd_name, lease -> ip_addr,
|
||||
&ddns_dhcid, ddns_ttl);
|
||||
&ddns_dhcid, ddns_ttl, 0);
|
||||
|
||||
if (rcode1 == ISC_R_SUCCESS) {
|
||||
if (ddns_fwd_name.len && ddns_rev_name.len)
|
||||
@@ -1025,7 +630,7 @@ int ddns_removals (struct lease *lease)
|
||||
in case the client did the update. */
|
||||
if (!find_bound_string (&ddns_fwd_name,
|
||||
lease -> scope, "ddns-client-fqdn"))
|
||||
return 0;
|
||||
goto try_rev;
|
||||
client_updated = 1;
|
||||
goto try_rev;
|
||||
}
|
||||
@@ -1041,7 +646,11 @@ int ddns_removals (struct lease *lease)
|
||||
/*
|
||||
* Perform removals.
|
||||
*/
|
||||
rcode = ddns_remove_a (&ddns_fwd_name, lease -> ip_addr, &ddns_dhcid);
|
||||
if (ddns_fwd_name.len)
|
||||
rcode = ddns_remove_a (&ddns_fwd_name,
|
||||
lease -> ip_addr, &ddns_dhcid);
|
||||
else
|
||||
rcode = ISC_R_SUCCESS;
|
||||
|
||||
if (rcode == ISC_R_SUCCESS) {
|
||||
result = 1;
|
||||
@@ -1055,6 +664,11 @@ int ddns_removals (struct lease *lease)
|
||||
if (client_updated)
|
||||
unset (lease -> scope,
|
||||
"ddns-client-fqdn");
|
||||
/* XXX this is to compensate for a bug in
|
||||
XXX 3.0rc8, and should be removed before
|
||||
XXX 3.0pl1. */
|
||||
else if (!ddns_fwd_name.len)
|
||||
unset (lease -> scope, "ddns-text");
|
||||
} else
|
||||
result = 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user