res_update.c revision 158782
1158782Sume#if !defined(lint) && !defined(SABER) 2158782Sumestatic const char rcsid[] = "$Id: res_update.c,v 1.6.2.4.4.2 2004/03/16 12:34:20 marka Exp $"; 3158782Sume#endif /* not lint */ 4158782Sume 5158782Sume/* 6158782Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 7158782Sume * Copyright (c) 1996-1999 by Internet Software Consortium. 8158782Sume * 9158782Sume * Permission to use, copy, modify, and distribute this software for any 10158782Sume * purpose with or without fee is hereby granted, provided that the above 11158782Sume * copyright notice and this permission notice appear in all copies. 12158782Sume * 13158782Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14158782Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15158782Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16158782Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17158782Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18158782Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19158782Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20158782Sume */ 21158782Sume 22158782Sume/* 23158782Sume * Based on the Dynamic DNS reference implementation by Viraj Bais 24158782Sume * <viraj_bais@ccm.fm.intel.com> 25158782Sume */ 26158782Sume 27158782Sume#include "port_before.h" 28158782Sume 29158782Sume#include <sys/param.h> 30158782Sume#include <sys/socket.h> 31158782Sume#include <sys/time.h> 32158782Sume 33158782Sume#include <netinet/in.h> 34158782Sume#include <arpa/inet.h> 35158782Sume#include <arpa/nameser.h> 36158782Sume 37158782Sume#include <errno.h> 38158782Sume#include <limits.h> 39158782Sume#include <netdb.h> 40158782Sume#include <res_update.h> 41158782Sume#include <stdarg.h> 42158782Sume#include <stdio.h> 43158782Sume#include <stdlib.h> 44158782Sume#include <string.h> 45158782Sume 46158782Sume#include <isc/list.h> 47158782Sume#include <resolv.h> 48158782Sume 49158782Sume#include "port_after.h" 50158782Sume#include "res_private.h" 51158782Sume 52158782Sume/* 53158782Sume * Separate a linked list of records into groups so that all records 54158782Sume * in a group will belong to a single zone on the nameserver. 55158782Sume * Create a dynamic update packet for each zone and send it to the 56158782Sume * nameservers for that zone, and await answer. 57158782Sume * Abort if error occurs in updating any zone. 58158782Sume * Return the number of zones updated on success, < 0 on error. 59158782Sume * 60158782Sume * On error, caller must deal with the unsynchronized zones 61158782Sume * eg. an A record might have been successfully added to the forward 62158782Sume * zone but the corresponding PTR record would be missing if error 63158782Sume * was encountered while updating the reverse zone. 64158782Sume */ 65158782Sume 66158782Sumestruct zonegrp { 67158782Sume char z_origin[MAXDNAME]; 68158782Sume ns_class z_class; 69158782Sume union res_sockaddr_union z_nsaddrs[MAXNS]; 70158782Sume int z_nscount; 71158782Sume int z_flags; 72158782Sume LIST(ns_updrec) z_rrlist; 73158782Sume LINK(struct zonegrp) z_link; 74158782Sume}; 75158782Sume 76158782Sume#define ZG_F_ZONESECTADDED 0x0001 77158782Sume 78158782Sume/* Forward. */ 79158782Sume 80158782Sumestatic void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); 81158782Sume 82158782Sume/* Macros. */ 83158782Sume 84158782Sume#define DPRINTF(x) do {\ 85158782Sume int save_errno = errno; \ 86158782Sume if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \ 87158782Sume errno = save_errno; \ 88158782Sume } while (0) 89158782Sume 90158782Sume/* Public. */ 91158782Sume 92158782Sumeint 93158782Sumeres_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) { 94158782Sume ns_updrec *rrecp; 95158782Sume u_char answer[PACKETSZ]; 96158782Sume u_char *packet; 97158782Sume struct zonegrp *zptr, tgrp; 98158782Sume LIST(struct zonegrp) zgrps; 99158782Sume int nzones = 0, nscount = 0, n; 100158782Sume union res_sockaddr_union nsaddrs[MAXNS]; 101158782Sume 102158782Sume packet = malloc(NS_MAXMSG); 103158782Sume if (packet == NULL) { 104158782Sume DPRINTF(("malloc failed")); 105158782Sume return (0); 106158782Sume } 107158782Sume /* Thread all of the updates onto a list of groups. */ 108158782Sume INIT_LIST(zgrps); 109158782Sume memset(&tgrp, 0, sizeof (tgrp)); 110158782Sume for (rrecp = rrecp_in; rrecp; 111158782Sume rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) { 112158782Sume int nscnt; 113158782Sume /* Find the origin for it if there is one. */ 114158782Sume tgrp.z_class = rrecp->r_class; 115158782Sume nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class, 116158782Sume RES_EXHAUSTIVE, tgrp.z_origin, 117158782Sume sizeof tgrp.z_origin, 118158782Sume tgrp.z_nsaddrs, MAXNS); 119158782Sume if (nscnt <= 0) { 120158782Sume DPRINTF(("res_findzonecut failed (%d)", nscnt)); 121158782Sume goto done; 122158782Sume } 123158782Sume tgrp.z_nscount = nscnt; 124158782Sume /* Find the group for it if there is one. */ 125158782Sume for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) 126158782Sume if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 && 127158782Sume tgrp.z_class == zptr->z_class) 128158782Sume break; 129158782Sume /* Make a group for it if there isn't one. */ 130158782Sume if (zptr == NULL) { 131158782Sume zptr = malloc(sizeof *zptr); 132158782Sume if (zptr == NULL) { 133158782Sume DPRINTF(("malloc failed")); 134158782Sume goto done; 135158782Sume } 136158782Sume *zptr = tgrp; 137158782Sume zptr->z_flags = 0; 138158782Sume INIT_LINK(zptr, z_link); 139158782Sume INIT_LIST(zptr->z_rrlist); 140158782Sume APPEND(zgrps, zptr, z_link); 141158782Sume } 142158782Sume /* Thread this rrecp onto the right group. */ 143158782Sume APPEND(zptr->z_rrlist, rrecp, r_glink); 144158782Sume } 145158782Sume 146158782Sume for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) { 147158782Sume /* Construct zone section and prepend it. */ 148158782Sume rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, 149158782Sume zptr->z_class, ns_t_soa, 0); 150158782Sume if (rrecp == NULL) { 151158782Sume DPRINTF(("res_mkupdrec failed")); 152158782Sume goto done; 153158782Sume } 154158782Sume PREPEND(zptr->z_rrlist, rrecp, r_glink); 155158782Sume zptr->z_flags |= ZG_F_ZONESECTADDED; 156158782Sume 157158782Sume /* Marshall the update message. */ 158158782Sume n = res_nmkupdate(statp, HEAD(zptr->z_rrlist), 159158782Sume packet, NS_MAXMSG); 160158782Sume DPRINTF(("res_mkupdate -> %d", n)); 161158782Sume if (n < 0) 162158782Sume goto done; 163158782Sume 164158782Sume /* Temporarily replace the resolver's nameserver set. */ 165158782Sume nscount = res_getservers(statp, nsaddrs, MAXNS); 166158782Sume res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount); 167158782Sume 168158782Sume /* Send the update and remember the result. */ 169158782Sume if (key != NULL) 170158782Sume n = res_nsendsigned(statp, packet, n, key, 171158782Sume answer, sizeof answer); 172158782Sume else 173158782Sume n = res_nsend(statp, packet, n, answer, sizeof answer); 174158782Sume if (n < 0) { 175158782Sume DPRINTF(("res_nsend: send error, n=%d (%s)\n", 176158782Sume n, strerror(errno))); 177158782Sume goto done; 178158782Sume } 179158782Sume if (((HEADER *)answer)->rcode == NOERROR) 180158782Sume nzones++; 181158782Sume 182158782Sume /* Restore resolver's nameserver set. */ 183158782Sume res_setservers(statp, nsaddrs, nscount); 184158782Sume nscount = 0; 185158782Sume } 186158782Sume done: 187158782Sume while (!EMPTY(zgrps)) { 188158782Sume zptr = HEAD(zgrps); 189158782Sume if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) 190158782Sume res_freeupdrec(HEAD(zptr->z_rrlist)); 191158782Sume UNLINK(zgrps, zptr, z_link); 192158782Sume free(zptr); 193158782Sume } 194158782Sume if (nscount != 0) 195158782Sume res_setservers(statp, nsaddrs, nscount); 196158782Sume 197158782Sume free(packet); 198158782Sume return (nzones); 199158782Sume} 200158782Sume 201158782Sume/* Private. */ 202158782Sume 203158782Sumestatic void 204158782Sumeres_dprintf(const char *fmt, ...) { 205158782Sume va_list ap; 206158782Sume 207158782Sume va_start(ap, fmt); 208158782Sume fputs(";; res_nupdate: ", stderr); 209158782Sume vfprintf(stderr, fmt, ap); 210158782Sume fputc('\n', stderr); 211158782Sume va_end(ap); 212158782Sume} 213