res_update.c revision 170244
1158782Sume#if !defined(lint) && !defined(SABER) 2170244Sumestatic const char rcsid[] = "$Id: res_update.c,v 1.12.18.1 2005/04/27 05:01:12 sra 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 22170244Sume/*! \file 23170244Sume * \brief 24158782Sume * Based on the Dynamic DNS reference implementation by Viraj Bais 25170244Sume * <viraj_bais@ccm.fm.intel.com> 26158782Sume */ 27158782Sume 28158787Sume#include <sys/cdefs.h> 29158787Sume__FBSDID("$FreeBSD: head/lib/libc/resolv/res_update.c 170244 2007-06-03 17:20:27Z ume $"); 30158787Sume 31158782Sume#include "port_before.h" 32158782Sume 33158782Sume#include <sys/param.h> 34158782Sume#include <sys/socket.h> 35158782Sume#include <sys/time.h> 36158782Sume 37158782Sume#include <netinet/in.h> 38158782Sume#include <arpa/inet.h> 39158782Sume#include <arpa/nameser.h> 40158782Sume 41158782Sume#include <errno.h> 42158782Sume#include <limits.h> 43158782Sume#include <netdb.h> 44158782Sume#include <res_update.h> 45158782Sume#include <stdarg.h> 46158782Sume#include <stdio.h> 47158782Sume#include <stdlib.h> 48158782Sume#include <string.h> 49158782Sume 50158782Sume#include <isc/list.h> 51158782Sume#include <resolv.h> 52158782Sume 53158782Sume#include "port_after.h" 54158782Sume#include "res_private.h" 55158782Sume 56170244Sume/*% 57158782Sume * Separate a linked list of records into groups so that all records 58158782Sume * in a group will belong to a single zone on the nameserver. 59158782Sume * Create a dynamic update packet for each zone and send it to the 60158782Sume * nameservers for that zone, and await answer. 61158782Sume * Abort if error occurs in updating any zone. 62158782Sume * Return the number of zones updated on success, < 0 on error. 63158782Sume * 64158782Sume * On error, caller must deal with the unsynchronized zones 65158782Sume * eg. an A record might have been successfully added to the forward 66158782Sume * zone but the corresponding PTR record would be missing if error 67158782Sume * was encountered while updating the reverse zone. 68158782Sume */ 69158782Sume 70158782Sumestruct zonegrp { 71158782Sume char z_origin[MAXDNAME]; 72158782Sume ns_class z_class; 73158782Sume union res_sockaddr_union z_nsaddrs[MAXNS]; 74158782Sume int z_nscount; 75158782Sume int z_flags; 76158782Sume LIST(ns_updrec) z_rrlist; 77158782Sume LINK(struct zonegrp) z_link; 78158782Sume}; 79158782Sume 80158782Sume#define ZG_F_ZONESECTADDED 0x0001 81158782Sume 82158782Sume/* Forward. */ 83158782Sume 84158782Sumestatic void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); 85158782Sume 86158782Sume/* Macros. */ 87158782Sume 88158782Sume#define DPRINTF(x) do {\ 89158782Sume int save_errno = errno; \ 90158782Sume if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \ 91158782Sume errno = save_errno; \ 92158782Sume } while (0) 93158782Sume 94158782Sume/* Public. */ 95158782Sume 96158782Sumeint 97158782Sumeres_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) { 98158782Sume ns_updrec *rrecp; 99158782Sume u_char answer[PACKETSZ]; 100158782Sume u_char *packet; 101158782Sume struct zonegrp *zptr, tgrp; 102158782Sume LIST(struct zonegrp) zgrps; 103158782Sume int nzones = 0, nscount = 0, n; 104158782Sume union res_sockaddr_union nsaddrs[MAXNS]; 105158782Sume 106158782Sume packet = malloc(NS_MAXMSG); 107158782Sume if (packet == NULL) { 108158782Sume DPRINTF(("malloc failed")); 109158782Sume return (0); 110158782Sume } 111158782Sume /* Thread all of the updates onto a list of groups. */ 112158782Sume INIT_LIST(zgrps); 113158782Sume memset(&tgrp, 0, sizeof (tgrp)); 114158782Sume for (rrecp = rrecp_in; rrecp; 115158782Sume rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) { 116158782Sume int nscnt; 117158782Sume /* Find the origin for it if there is one. */ 118158782Sume tgrp.z_class = rrecp->r_class; 119158782Sume nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class, 120158782Sume RES_EXHAUSTIVE, tgrp.z_origin, 121158782Sume sizeof tgrp.z_origin, 122158782Sume tgrp.z_nsaddrs, MAXNS); 123158782Sume if (nscnt <= 0) { 124158782Sume DPRINTF(("res_findzonecut failed (%d)", nscnt)); 125158782Sume goto done; 126158782Sume } 127158782Sume tgrp.z_nscount = nscnt; 128158782Sume /* Find the group for it if there is one. */ 129158782Sume for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) 130158782Sume if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 && 131158782Sume tgrp.z_class == zptr->z_class) 132158782Sume break; 133158782Sume /* Make a group for it if there isn't one. */ 134158782Sume if (zptr == NULL) { 135158782Sume zptr = malloc(sizeof *zptr); 136158782Sume if (zptr == NULL) { 137158782Sume DPRINTF(("malloc failed")); 138158782Sume goto done; 139158782Sume } 140158782Sume *zptr = tgrp; 141158782Sume zptr->z_flags = 0; 142158782Sume INIT_LINK(zptr, z_link); 143158782Sume INIT_LIST(zptr->z_rrlist); 144158782Sume APPEND(zgrps, zptr, z_link); 145158782Sume } 146158782Sume /* Thread this rrecp onto the right group. */ 147158782Sume APPEND(zptr->z_rrlist, rrecp, r_glink); 148158782Sume } 149158782Sume 150158782Sume for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) { 151158782Sume /* Construct zone section and prepend it. */ 152158782Sume rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, 153158782Sume zptr->z_class, ns_t_soa, 0); 154158782Sume if (rrecp == NULL) { 155158782Sume DPRINTF(("res_mkupdrec failed")); 156158782Sume goto done; 157158782Sume } 158158782Sume PREPEND(zptr->z_rrlist, rrecp, r_glink); 159158782Sume zptr->z_flags |= ZG_F_ZONESECTADDED; 160158782Sume 161158782Sume /* Marshall the update message. */ 162158782Sume n = res_nmkupdate(statp, HEAD(zptr->z_rrlist), 163158782Sume packet, NS_MAXMSG); 164158782Sume DPRINTF(("res_mkupdate -> %d", n)); 165158782Sume if (n < 0) 166158782Sume goto done; 167158782Sume 168158782Sume /* Temporarily replace the resolver's nameserver set. */ 169158782Sume nscount = res_getservers(statp, nsaddrs, MAXNS); 170158782Sume res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount); 171158782Sume 172158782Sume /* Send the update and remember the result. */ 173158787Sume if (key != NULL) { 174158787Sume#ifdef _LIBC 175158787Sume DPRINTF(("TSIG is not supported\n")); 176158787Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 177158787Sume goto done; 178158787Sume#else 179158782Sume n = res_nsendsigned(statp, packet, n, key, 180158782Sume answer, sizeof answer); 181158787Sume#endif 182158787Sume } else 183158782Sume n = res_nsend(statp, packet, n, answer, sizeof answer); 184158782Sume if (n < 0) { 185158782Sume DPRINTF(("res_nsend: send error, n=%d (%s)\n", 186158782Sume n, strerror(errno))); 187158782Sume goto done; 188158782Sume } 189158782Sume if (((HEADER *)answer)->rcode == NOERROR) 190158782Sume nzones++; 191158782Sume 192158782Sume /* Restore resolver's nameserver set. */ 193158782Sume res_setservers(statp, nsaddrs, nscount); 194158782Sume nscount = 0; 195158782Sume } 196158782Sume done: 197158782Sume while (!EMPTY(zgrps)) { 198158782Sume zptr = HEAD(zgrps); 199158782Sume if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) 200158782Sume res_freeupdrec(HEAD(zptr->z_rrlist)); 201158782Sume UNLINK(zgrps, zptr, z_link); 202158782Sume free(zptr); 203158782Sume } 204158782Sume if (nscount != 0) 205158782Sume res_setservers(statp, nsaddrs, nscount); 206158782Sume 207158782Sume free(packet); 208158782Sume return (nzones); 209158782Sume} 210158782Sume 211158782Sume/* Private. */ 212158782Sume 213158782Sumestatic void 214158782Sumeres_dprintf(const char *fmt, ...) { 215158782Sume va_list ap; 216158782Sume 217158782Sume va_start(ap, fmt); 218158782Sume fputs(";; res_nupdate: ", stderr); 219158782Sume vfprintf(stderr, fmt, ap); 220158782Sume fputc('\n', stderr); 221158782Sume va_end(ap); 222158782Sume} 223