xref: /freebsd/lib/libc/resolv/res_update.c (revision dc36d6f9)
1f62c4786SHajimu UMEMOTO 
26e778a7eSPedro F. Giffuni /*-
36e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
46e778a7eSPedro 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