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