1f62c4786SHajimu UMEMOTO #if !defined(lint) && !defined(SABER) 2dde4a85dSHajimu UMEMOTO static const char rcsid[] = "$Id: res_update.c,v 1.12.18.1 2005/04/27 05:01:12 sra Exp $"; 3f62c4786SHajimu UMEMOTO #endif /* not lint */ 4f62c4786SHajimu UMEMOTO 5f62c4786SHajimu UMEMOTO /* 6f62c4786SHajimu UMEMOTO * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 7f62c4786SHajimu UMEMOTO * Copyright (c) 1996-1999 by Internet Software Consortium. 8f62c4786SHajimu UMEMOTO * 9f62c4786SHajimu UMEMOTO * Permission to use, copy, modify, and distribute this software for any 10f62c4786SHajimu UMEMOTO * purpose with or without fee is hereby granted, provided that the above 11f62c4786SHajimu UMEMOTO * copyright notice and this permission notice appear in all copies. 12f62c4786SHajimu UMEMOTO * 13f62c4786SHajimu UMEMOTO * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14f62c4786SHajimu UMEMOTO * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15f62c4786SHajimu UMEMOTO * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16f62c4786SHajimu UMEMOTO * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17f62c4786SHajimu UMEMOTO * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18f62c4786SHajimu UMEMOTO * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19f62c4786SHajimu UMEMOTO * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20f62c4786SHajimu UMEMOTO */ 21f62c4786SHajimu UMEMOTO 22dde4a85dSHajimu UMEMOTO /*! \file 23dde4a85dSHajimu UMEMOTO * \brief 24f62c4786SHajimu UMEMOTO * Based on the Dynamic DNS reference implementation by Viraj Bais 25dde4a85dSHajimu UMEMOTO * <viraj_bais@ccm.fm.intel.com> 26f62c4786SHajimu UMEMOTO */ 27f62c4786SHajimu UMEMOTO 28d808369aSHajimu UMEMOTO #include <sys/cdefs.h> 29d808369aSHajimu UMEMOTO __FBSDID("$FreeBSD$"); 30d808369aSHajimu UMEMOTO 31f62c4786SHajimu UMEMOTO #include "port_before.h" 32f62c4786SHajimu UMEMOTO 33f62c4786SHajimu UMEMOTO #include <sys/param.h> 34f62c4786SHajimu UMEMOTO #include <sys/socket.h> 35f62c4786SHajimu UMEMOTO #include <sys/time.h> 36f62c4786SHajimu UMEMOTO 37f62c4786SHajimu UMEMOTO #include <netinet/in.h> 38f62c4786SHajimu UMEMOTO #include <arpa/inet.h> 39f62c4786SHajimu UMEMOTO #include <arpa/nameser.h> 40f62c4786SHajimu UMEMOTO 41f62c4786SHajimu UMEMOTO #include <errno.h> 42f62c4786SHajimu UMEMOTO #include <limits.h> 43f62c4786SHajimu UMEMOTO #include <netdb.h> 44f62c4786SHajimu UMEMOTO #include <res_update.h> 45f62c4786SHajimu UMEMOTO #include <stdarg.h> 46f62c4786SHajimu UMEMOTO #include <stdio.h> 47f62c4786SHajimu UMEMOTO #include <stdlib.h> 48f62c4786SHajimu UMEMOTO #include <string.h> 49f62c4786SHajimu UMEMOTO 50f62c4786SHajimu UMEMOTO #include <isc/list.h> 51f62c4786SHajimu UMEMOTO #include <resolv.h> 52f62c4786SHajimu UMEMOTO 53f62c4786SHajimu UMEMOTO #include "port_after.h" 54f62c4786SHajimu UMEMOTO #include "res_private.h" 55f62c4786SHajimu UMEMOTO 56dde4a85dSHajimu UMEMOTO /*% 57f62c4786SHajimu UMEMOTO * Separate a linked list of records into groups so that all records 58f62c4786SHajimu UMEMOTO * in a group will belong to a single zone on the nameserver. 59f62c4786SHajimu UMEMOTO * Create a dynamic update packet for each zone and send it to the 60f62c4786SHajimu UMEMOTO * nameservers for that zone, and await answer. 61f62c4786SHajimu UMEMOTO * Abort if error occurs in updating any zone. 62f62c4786SHajimu UMEMOTO * Return the number of zones updated on success, < 0 on error. 63f62c4786SHajimu UMEMOTO * 64f62c4786SHajimu UMEMOTO * On error, caller must deal with the unsynchronized zones 65f62c4786SHajimu UMEMOTO * eg. an A record might have been successfully added to the forward 66f62c4786SHajimu UMEMOTO * zone but the corresponding PTR record would be missing if error 67f62c4786SHajimu UMEMOTO * was encountered while updating the reverse zone. 68f62c4786SHajimu UMEMOTO */ 69f62c4786SHajimu UMEMOTO 70f62c4786SHajimu UMEMOTO struct zonegrp { 71f62c4786SHajimu UMEMOTO char z_origin[MAXDNAME]; 72f62c4786SHajimu UMEMOTO ns_class z_class; 73f62c4786SHajimu UMEMOTO union res_sockaddr_union z_nsaddrs[MAXNS]; 74f62c4786SHajimu UMEMOTO int z_nscount; 75f62c4786SHajimu UMEMOTO int z_flags; 76f62c4786SHajimu UMEMOTO LIST(ns_updrec) z_rrlist; 77f62c4786SHajimu UMEMOTO LINK(struct zonegrp) z_link; 78f62c4786SHajimu UMEMOTO }; 79f62c4786SHajimu UMEMOTO 80f62c4786SHajimu UMEMOTO #define ZG_F_ZONESECTADDED 0x0001 81f62c4786SHajimu UMEMOTO 82f62c4786SHajimu UMEMOTO /* Forward. */ 83f62c4786SHajimu UMEMOTO 84f62c4786SHajimu UMEMOTO static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); 85f62c4786SHajimu UMEMOTO 86f62c4786SHajimu UMEMOTO /* Macros. */ 87f62c4786SHajimu UMEMOTO 88f62c4786SHajimu UMEMOTO #define DPRINTF(x) do {\ 89f62c4786SHajimu UMEMOTO int save_errno = errno; \ 90f62c4786SHajimu UMEMOTO if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \ 91f62c4786SHajimu UMEMOTO errno = save_errno; \ 92f62c4786SHajimu UMEMOTO } while (0) 93f62c4786SHajimu UMEMOTO 94f62c4786SHajimu UMEMOTO /* Public. */ 95f62c4786SHajimu UMEMOTO 96f62c4786SHajimu UMEMOTO int 97f62c4786SHajimu UMEMOTO res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) { 98f62c4786SHajimu UMEMOTO ns_updrec *rrecp; 99f62c4786SHajimu UMEMOTO u_char answer[PACKETSZ]; 100f62c4786SHajimu UMEMOTO u_char *packet; 101f62c4786SHajimu UMEMOTO struct zonegrp *zptr, tgrp; 102f62c4786SHajimu UMEMOTO LIST(struct zonegrp) zgrps; 103f62c4786SHajimu UMEMOTO int nzones = 0, nscount = 0, n; 104f62c4786SHajimu UMEMOTO union res_sockaddr_union nsaddrs[MAXNS]; 105f62c4786SHajimu UMEMOTO 106f62c4786SHajimu UMEMOTO packet = malloc(NS_MAXMSG); 107f62c4786SHajimu UMEMOTO if (packet == NULL) { 108f62c4786SHajimu UMEMOTO DPRINTF(("malloc failed")); 109f62c4786SHajimu UMEMOTO return (0); 110f62c4786SHajimu UMEMOTO } 111f62c4786SHajimu UMEMOTO /* Thread all of the updates onto a list of groups. */ 112f62c4786SHajimu UMEMOTO INIT_LIST(zgrps); 113f62c4786SHajimu UMEMOTO memset(&tgrp, 0, sizeof (tgrp)); 114f62c4786SHajimu UMEMOTO for (rrecp = rrecp_in; rrecp; 115f62c4786SHajimu UMEMOTO rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) { 116f62c4786SHajimu UMEMOTO int nscnt; 117f62c4786SHajimu UMEMOTO /* Find the origin for it if there is one. */ 118f62c4786SHajimu UMEMOTO tgrp.z_class = rrecp->r_class; 119f62c4786SHajimu UMEMOTO nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class, 120f62c4786SHajimu UMEMOTO RES_EXHAUSTIVE, tgrp.z_origin, 121f62c4786SHajimu UMEMOTO sizeof tgrp.z_origin, 122f62c4786SHajimu UMEMOTO tgrp.z_nsaddrs, MAXNS); 123f62c4786SHajimu UMEMOTO if (nscnt <= 0) { 124f62c4786SHajimu UMEMOTO DPRINTF(("res_findzonecut failed (%d)", nscnt)); 125f62c4786SHajimu UMEMOTO goto done; 126f62c4786SHajimu UMEMOTO } 127f62c4786SHajimu UMEMOTO tgrp.z_nscount = nscnt; 128f62c4786SHajimu UMEMOTO /* Find the group for it if there is one. */ 129f62c4786SHajimu UMEMOTO for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) 130f62c4786SHajimu UMEMOTO if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 && 131f62c4786SHajimu UMEMOTO tgrp.z_class == zptr->z_class) 132f62c4786SHajimu UMEMOTO break; 133f62c4786SHajimu UMEMOTO /* Make a group for it if there isn't one. */ 134f62c4786SHajimu UMEMOTO if (zptr == NULL) { 135f62c4786SHajimu UMEMOTO zptr = malloc(sizeof *zptr); 136f62c4786SHajimu UMEMOTO if (zptr == NULL) { 137f62c4786SHajimu UMEMOTO DPRINTF(("malloc failed")); 138f62c4786SHajimu UMEMOTO goto done; 139f62c4786SHajimu UMEMOTO } 140f62c4786SHajimu UMEMOTO *zptr = tgrp; 141f62c4786SHajimu UMEMOTO zptr->z_flags = 0; 142f62c4786SHajimu UMEMOTO INIT_LINK(zptr, z_link); 143f62c4786SHajimu UMEMOTO INIT_LIST(zptr->z_rrlist); 144f62c4786SHajimu UMEMOTO APPEND(zgrps, zptr, z_link); 145f62c4786SHajimu UMEMOTO } 146f62c4786SHajimu UMEMOTO /* Thread this rrecp onto the right group. */ 147f62c4786SHajimu UMEMOTO APPEND(zptr->z_rrlist, rrecp, r_glink); 148f62c4786SHajimu UMEMOTO } 149f62c4786SHajimu UMEMOTO 150f62c4786SHajimu UMEMOTO for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) { 151f62c4786SHajimu UMEMOTO /* Construct zone section and prepend it. */ 152f62c4786SHajimu UMEMOTO rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, 153f62c4786SHajimu UMEMOTO zptr->z_class, ns_t_soa, 0); 154f62c4786SHajimu UMEMOTO if (rrecp == NULL) { 155f62c4786SHajimu UMEMOTO DPRINTF(("res_mkupdrec failed")); 156f62c4786SHajimu UMEMOTO goto done; 157f62c4786SHajimu UMEMOTO } 158f62c4786SHajimu UMEMOTO PREPEND(zptr->z_rrlist, rrecp, r_glink); 159f62c4786SHajimu UMEMOTO zptr->z_flags |= ZG_F_ZONESECTADDED; 160f62c4786SHajimu UMEMOTO 161f62c4786SHajimu UMEMOTO /* Marshall the update message. */ 162f62c4786SHajimu UMEMOTO n = res_nmkupdate(statp, HEAD(zptr->z_rrlist), 163f62c4786SHajimu UMEMOTO packet, NS_MAXMSG); 164f62c4786SHajimu UMEMOTO DPRINTF(("res_mkupdate -> %d", n)); 165f62c4786SHajimu UMEMOTO if (n < 0) 166f62c4786SHajimu UMEMOTO goto done; 167f62c4786SHajimu UMEMOTO 168f62c4786SHajimu UMEMOTO /* Temporarily replace the resolver's nameserver set. */ 169f62c4786SHajimu UMEMOTO nscount = res_getservers(statp, nsaddrs, MAXNS); 170f62c4786SHajimu UMEMOTO res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount); 171f62c4786SHajimu UMEMOTO 172f62c4786SHajimu UMEMOTO /* Send the update and remember the result. */ 173d808369aSHajimu UMEMOTO if (key != NULL) { 174d808369aSHajimu UMEMOTO #ifdef _LIBC 175d808369aSHajimu UMEMOTO DPRINTF(("TSIG is not supported\n")); 176d808369aSHajimu UMEMOTO RES_SET_H_ERRNO(statp, NO_RECOVERY); 177d808369aSHajimu UMEMOTO goto done; 178d808369aSHajimu UMEMOTO #else 179f62c4786SHajimu UMEMOTO n = res_nsendsigned(statp, packet, n, key, 180f62c4786SHajimu UMEMOTO answer, sizeof answer); 181d808369aSHajimu UMEMOTO #endif 182d808369aSHajimu UMEMOTO } else 183f62c4786SHajimu UMEMOTO n = res_nsend(statp, packet, n, answer, sizeof answer); 184f62c4786SHajimu UMEMOTO if (n < 0) { 185f62c4786SHajimu UMEMOTO DPRINTF(("res_nsend: send error, n=%d (%s)\n", 186f62c4786SHajimu UMEMOTO n, strerror(errno))); 187f62c4786SHajimu UMEMOTO goto done; 188f62c4786SHajimu UMEMOTO } 189f62c4786SHajimu UMEMOTO if (((HEADER *)answer)->rcode == NOERROR) 190f62c4786SHajimu UMEMOTO nzones++; 191f62c4786SHajimu UMEMOTO 192f62c4786SHajimu UMEMOTO /* Restore resolver's nameserver set. */ 193f62c4786SHajimu UMEMOTO res_setservers(statp, nsaddrs, nscount); 194f62c4786SHajimu UMEMOTO nscount = 0; 195f62c4786SHajimu UMEMOTO } 196f62c4786SHajimu UMEMOTO done: 197f62c4786SHajimu UMEMOTO while (!EMPTY(zgrps)) { 198f62c4786SHajimu UMEMOTO zptr = HEAD(zgrps); 199f62c4786SHajimu UMEMOTO if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) 200f62c4786SHajimu UMEMOTO res_freeupdrec(HEAD(zptr->z_rrlist)); 201f62c4786SHajimu UMEMOTO UNLINK(zgrps, zptr, z_link); 202f62c4786SHajimu UMEMOTO free(zptr); 203f62c4786SHajimu UMEMOTO } 204f62c4786SHajimu UMEMOTO if (nscount != 0) 205f62c4786SHajimu UMEMOTO res_setservers(statp, nsaddrs, nscount); 206f62c4786SHajimu UMEMOTO 207f62c4786SHajimu UMEMOTO free(packet); 208f62c4786SHajimu UMEMOTO return (nzones); 209f62c4786SHajimu UMEMOTO } 210f62c4786SHajimu UMEMOTO 211f62c4786SHajimu UMEMOTO /* Private. */ 212f62c4786SHajimu UMEMOTO 213f62c4786SHajimu UMEMOTO static void 214f62c4786SHajimu UMEMOTO res_dprintf(const char *fmt, ...) { 215f62c4786SHajimu UMEMOTO va_list ap; 216f62c4786SHajimu UMEMOTO 217f62c4786SHajimu UMEMOTO va_start(ap, fmt); 218f62c4786SHajimu UMEMOTO fputs(";; res_nupdate: ", stderr); 219f62c4786SHajimu UMEMOTO vfprintf(stderr, fmt, ap); 220f62c4786SHajimu UMEMOTO fputc('\n', stderr); 221f62c4786SHajimu UMEMOTO va_end(ap); 222f62c4786SHajimu UMEMOTO } 223