2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-09-05 16:55:10 +00:00
Files
isc-dhcp/common/nsupdate.c
1999-09-16 01:19:52 +00:00

510 lines
14 KiB
C

/* nsupdate.c
Tables of information... */
/*
* Copyright (c) 1999 Internet Software Consortium.
* Use is subject to license terms which appear in the file named
* ISC-LICENSE that should have accompanied this file when you
* received it. If a file named ISC-LICENSE did not accompany this
* file, or you are not sure the one you have is correct, you may
* obtain an applicable copy of the license at:
*
* http://www.isc.org/isc-license-1.0.html.
*
* This file is part of the ISC DHCP distribution. The documentation
* associated with this file is listed in the file DOCUMENTATION,
* included in the top-level directory of this release.
*
* Support and other services are available for ISC products - see
* http://www.isc.org for more information.
*
* Note: file is currently based on work done by Brian Murrell, Irina
* Goble and others. The copyright message is not final.
*/
#ifndef lint
static char copyright[] =
"$Id: nsupdate.c,v 1.8 1999/09/16 01:14:52 mellon Exp $ Copyright (c) 1999 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
#if defined (NSUPDATE)
/* Yet another new plan.
First thing to be done is to determine if a change actually needs to be
done. This can be done by figuring out the hostname.domain and revname
and then comparing them to the lease->ddns* values. Only make the changes
necessary which can be any combination and number of remove A, add A,
remove PTR, add PTR */
#if 0
/* Return the reverse name of a lease. */
char *ddns_rev_name(lease, state, packet)
struct lease *lease;
struct lease_state *state;
struct packet *packet;
{
struct option_cache *oc = NULL;
struct data_string d;
static char revname[MAXDNAME];
char revdomain[MAXDNAME];
revname[0]='\0';
revdomain[0]='\0';
/* Figure out what reverse domain to update
First take the scoped "ddns-rev-domainname" option if present
then assume d.c.b.a.in-addr.arpa. if not present
error if neither are present */
oc = lookup_option (&server_universe, state -> options,
SV_DDNS_REV_DOMAIN_NAME);
memset (&d, 0, sizeof d);
if (oc && evaluate_option_cache (&d, packet, lease,
packet -> options, state -> options,
oc)) {
memcpy(revdomain, d.data, d.len);
revdomain[d.len]='\0';
data_string_forget (&d, "nsupdate");
} else
strcpy(revdomain, "in-addr.arpa");
if ( lease->ip_addr.len != 4 ) { /* IPv4 */
log_error("unsupported IP address length: %d",
lease->ip_addr.len);
return NULL;
}
#if defined (NO_SNPRINTF)
sprintf(revname, "%d.%d.%d.%d.%s.",
lease->ip_addr.iabuf[3], lease->ip_addr.iabuf[2],
lease->ip_addr.iabuf[1], lease->ip_addr.iabuf[0], revdomain);
#else
snprintf(revname, MAXDNAME, "%d.%d.%d.%d.%s.",
lease->ip_addr.iabuf[3], lease->ip_addr.iabuf[2],
lease->ip_addr.iabuf[1], lease->ip_addr.iabuf[0], revdomain);
#endif
return revname;
}
/* Return the forward name of a lease. */
char *ddns_fwd_name(lease, state, packet)
struct lease *lease;
struct lease_state *state;
struct packet *packet;
{
struct option_cache *oc = NULL;
struct data_string d;
static char hostname[MAXDNAME];
char domain[MAXDNAME];
domain[0]='\0';
hostname[0]='\0';
/* Figure out the domain name of a lease.
First take the scoped "ddns-domainname" option if present
then the dhcp option "domain-name" if present
error if neither are present */
oc = lookup_option (&server_universe, state -> options,
SV_DDNS_DOMAIN_NAME);
memset (&d, 0, sizeof d);
if (oc && evaluate_option_cache (&d, packet, lease,
packet -> options, state -> options,
oc)) {
memcpy(domain, d.data, d.len);
domain[d.len]='\0';
data_string_forget (&d, "nsupdate");
} else {
oc = lookup_option (&dhcp_universe, state -> options,
DHO_DOMAIN_NAME);
memset (&d, 0, sizeof d);
if (oc && evaluate_option_cache (&d, packet, lease,
packet -> options,
state -> options,
oc)) {
memcpy(domain, d.data, d.len);
domain[d.len]='\0';
data_string_forget (&d, "nsupdate");
} else {
log_info("nsupdate failed: %s",
"unknown domain for update");
return NULL;
}
}
/* Figure out what host in the domain to assign to.
First take the scoped "ddns-hostname" option
then the dhcp option "host-name" if present
then the dhcp host_decl "name" if present
error if neither are present. */
oc = lookup_option (&server_universe, state -> options,
SV_DDNS_HOST_NAME);
memset (&d, 0, sizeof d);
if (oc && evaluate_option_cache (&d, packet, lease,
packet -> options, state -> options,
oc)) {
memcpy(hostname, d.data, d.len);
hostname[d.len]='\0';
data_string_forget (&d, "nsupdate");
} else {
oc = lookup_option (&dhcp_universe,
packet -> options, DHO_HOST_NAME);
memset (&d, 0, sizeof d);
if (oc && evaluate_option_cache (&d, packet, lease,
packet -> options,
state -> options, oc)) {
memcpy(hostname, d.data, d.len);
hostname[d.len]='\0';
data_string_forget (&d, "nsupdate");
} else {
if (lease -> host && lease -> host -> name &&
strcmp(lease -> host -> name, "")!=0)
strcpy(hostname, lease -> host -> name);
else {
log_info("nsupdate failed: %s",
"unknown hostname for update");
return NULL;
}
}
}
if ( !res_hnok(hostname) ) {
log_error("nsupdate: Bad hostname \"%s\"", hostname);
return NULL;
}
#if defined (NO_SNPRINTF)
if (sprintf(hostname, "%s.%s.", hostname, domain) < 0) {
log_error("nsupdate: Build FQDN failed");
return NULL;
}
#else
if (snprintf(hostname, MAXDNAME, "%s.%s.", hostname, domain) < 0) {
log_error("nsupdate: Build FQDN failed");
return NULL;
}
#endif
return hostname;
}
#endif
static int nsupdateA(hostname, ip_addr, ttl, opcode)
char *hostname;
unsigned char *ip_addr;
u_int32_t ttl;
int opcode;
{
int z;
ns_updrec *u, *n;
switch (opcode) {
case ADD:
if (!(u = res_mkupdrec(S_PREREQ, hostname, C_IN, T_A, 0)))
return 0;
u->r_opcode = NXRRSET; u->r_data = NULL; u->r_size = 0;
if (!(n = res_mkupdrec(S_UPDATE, hostname, C_IN, T_A, ttl))) {
res_freeupdrec(u);
return 0;
}
n->r_opcode = opcode;
n->r_data = ip_addr;
n->r_size = strlen((const char *)n->r_data);
u->r_next = n;
z = res_update(u);
log_info("add %s: %s %d IN A %s",
z == 1 ? "succeeded" : "failed", hostname, ttl,
n->r_data);
res_freeupdrec(u);
res_freeupdrec(n);
/* do we really need to do this? If so, it needs to be done elsewehere as
this function is strictly for manipulating the A record
if (z < 1)
return 0;
*/
/* delete all PTR RRs with the same ip address. Wow! */
/*
if (!(u = res_mkupdrec(S_UPDATE, revname, C_IN, T_PTR, 0)))
return 0;
u->r_opcode = DELETE; u->r_data = NULL; u->r_size = 0;
log_info("cleaning all PTR RRs for %s", revname);
res_update(u);
res_freeupdrec(u);
*/
break;
case DELETE:
ttl = 0;
if (!(u = res_mkupdrec(S_UPDATE, hostname, C_IN, T_A, ttl)))
return 0;
u->r_opcode = opcode;
u->r_data = ip_addr;
u->r_size = strlen((const char *)u->r_data);
z = res_update(u);
log_info("delete %s: %s %d IN A %s",
z == 1 ? "succeeded" : "failed",
hostname, ttl, u->r_data);
res_freeupdrec(u);
break;
}
return z;
}
static int nsupdatePTR(revname, hostname, ttl, opcode)
unsigned char *hostname;
char *revname;
u_int32_t ttl;
int opcode;
{
int z;
ns_updrec *u;
if (opcode == DELETE)
ttl = 0;
if (!(u = res_mkupdrec(S_UPDATE, revname, C_IN, T_PTR, ttl)))
return 0;
u->r_opcode = opcode;
u->r_data = hostname;
u->r_size = strlen((const char *)u->r_data);
z = res_update(u);
log_info("%s %s: %s %d IN PTR %s",
opcode == ADD ? "add" :
"delete", z == 1 ? "succeeded" : "failed",
revname, ttl, hostname);
res_freeupdrec(u);
return z;
}
#if 0
void nsupdate(lease, state, packet, opcode)
struct lease *lease;
struct lease_state *state;
struct packet *packet;
int opcode;
{
char *hostname, *revname;
u_int32_t ttl = 0;
return;
if (!(opcode == ADD || opcode == DELETE))
return;
if (!packet){
log_info("invalid pointer at %s:%d",
__FILE__, __LINE__-2);
return;
}
if (!packet -> options) {
log_info("invalid pointer at %s:%d",
__FILE__, __LINE__-2);
return;
}
if (!lease){
log_info("invalid pointer at %s:%d",
__FILE__, __LINE__-2);
return;
}
switch (opcode) {
case ADD:
if (!state) {
log_info("invalid pointer at %s:%d",
__FILE__, __LINE__-2);
return;
}
if (!state -> options) {
log_info("invalid pointer at %s:%d",
__FILE__, __LINE__-2);
return;
}
hostname = ddns_fwd_name(lease, state, packet);
if (!hostname) /* there is nothing we can do now */
return;
revname = ddns_rev_name(lease, state, packet);
if (state -> offered_expiry > lease -> timestamp)
ttl = state -> offered_expiry -
lease->timestamp;
else
log_error("nsupdate: ttl < 0");
/* delete an existing A if the one to be added is different */
if (lease -> ddns_fwd_name &&
strcmp(hostname, lease -> ddns_fwd_name)) {
int y;
y=nsupdateA(lease -> ddns_fwd_name,
piaddr(lease->ip_addr), ttl, DELETE);
/* delete an existing PTR if new one is different */
if (lease -> ddns_rev_name &&
(strcmp(hostname, lease -> ddns_fwd_name) ||
strcmp(revname, lease -> ddns_rev_name)) &&
nsupdatePTR(revname, lease -> ddns_fwd_name,
ttl, DELETE)) {
/* clear the forward DNS name pointer */
if (lease -> ddns_rev_name)
dfree(lease -> ddns_rev_name,
"nsupdate");
lease -> ddns_rev_name = 0;
}
if (y) {
/* clear the forward DNS name pointer */
if (lease -> ddns_fwd_name)
dfree(lease -> ddns_fwd_name,
"nsupdate");
lease -> ddns_fwd_name = 0;
}
}
/* only update if there is no A record there already */
if (!lease -> ddns_fwd_name) {
int z;
z=nsupdateA(hostname, piaddr(lease->ip_addr), ttl, ADD);
if (z < 1)
return;
/* remember this in the lease structure for release */
lease -> ddns_fwd_name = dmalloc(strlen(hostname) + 1,
"nsupdate");
strcpy (lease -> ddns_fwd_name, hostname);
}
if (!revname) /* there is nothing more we can do now */
return;
/* This is where a deletion of all PTRs for this addy could
go, but I am reluctant to overburden the DHCP and DNS
servers with requests that should be invalid if this is
really a problem then somebody else is inserting PTRs and
they should stop, rather than this being turned into a
garbage cleanup routine */
if (!lease -> ddns_rev_name) {
/* add a PTR RR */
if (nsupdatePTR(revname, hostname, ttl, ADD)) {
/* remember in the lease struct for a release */
lease -> ddns_rev_name =
dmalloc(strlen(revname) + 1, "nsupdate");
strcpy (lease -> ddns_rev_name, revname);
}
}
break;
case DELETE:
ttl = 0;
if (lease -> ddns_fwd_name) {
int y;
y = nsupdateA(lease -> ddns_fwd_name,
piaddr(lease->ip_addr), ttl, DELETE);
if (lease -> ddns_rev_name &&
nsupdatePTR(lease -> ddns_rev_name,
lease -> ddns_fwd_name,
ttl, opcode)) {
/* clear the reverse DNS name pointer */
if (lease -> ddns_rev_name)
dfree(lease -> ddns_rev_name,
"nsupdate");
lease -> ddns_rev_name = 0;
}
if (y) {
/* clear the forward DNS name pointer */
if (lease -> ddns_fwd_name)
dfree(lease -> ddns_fwd_name,
"nsupdate");
lease -> ddns_fwd_name = 0;
}
}
break;
}
return;
}
#endif
/* public function to update an A record if needed */
int updateA(struct data_string *lhs, struct data_string *rhs, unsigned int ttl,
struct lease *lease)
{
static char hostname[MAXDNAME];
static char ipaddr[MAXDNAME];
hostname[0] = '\0';
strncat(hostname, (const char *)lhs->data, lhs->len);
hostname[lhs->len] = '\0';
ipaddr[0] = '\0';
strncat(ipaddr, (const char *)rhs->data, rhs->len);
ipaddr[rhs->len] = '\0';
/* delete an existing A if the one to be added is different */
if (lease -> ddns_fwd_name &&
strcmp(hostname, lease -> ddns_fwd_name)) {
int y;
y=nsupdateA(lease -> ddns_fwd_name, ipaddr, 0, DELETE);
if (y) {
/* clear the forward DNS name pointer */
if (lease -> ddns_fwd_name)
dfree(lease -> ddns_fwd_name, "nsupdate");
lease -> ddns_fwd_name = 0;
}
}
/* only update if there is no A record there already */
if (!lease -> ddns_fwd_name) {
int y;
y=nsupdateA(hostname, ipaddr, ttl, ADD);
if (y < 1)
return 0;
/* remember this in the lease structure for release */
lease -> ddns_fwd_name = dmalloc(strlen(hostname) + 1,
"nsupdate");
strcpy (lease -> ddns_fwd_name, hostname);
}
return 1;
}
/* public function to update an A record if needed */
int updatePTR(struct data_string *lhs, struct data_string *rhs,
unsigned int ttl, struct lease *lease)
{
static char hostname[MAXDNAME];
static char revname[MAXDNAME];
revname[0] = '\0';
strncat(revname, (const char *)lhs->data, lhs->len);
revname[lhs->len] = '\0';
hostname[0] = '\0';
strncat(hostname, (const char *)rhs->data, rhs->len);
hostname[rhs->len] = '\0';
/* delete an existing PTR if the one to be added is different */
if (lease -> ddns_rev_name &&
strcmp(revname, lease -> ddns_rev_name)) {
int y;
y=nsupdatePTR(revname, hostname, 0, DELETE);
if (y) {
/* clear the reverse DNS name pointer */
if (lease -> ddns_rev_name)
dfree(lease -> ddns_rev_name, "nsupdate");
lease -> ddns_rev_name = 0;
}
}
/* only update if there is no PTR record there already */
if (!lease -> ddns_rev_name) {
int y;
y=nsupdatePTR(revname, hostname, ttl, ADD);
if (y < 1)
return 0;
/* remember this in the lease structure for release */
lease -> ddns_rev_name = dmalloc(strlen(revname) + 1,
"nsupdate");
strcpy (lease -> ddns_rev_name, revname);
}
return 1;
}
#endif /* defined (NSUPDATE) */