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