1 /*
2  * Copyright (c) 2004  Morettoni Luca <luca@morettoni.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $Id: zonenotify.c,v 1.4 2004/07/19 12:37:04 luca Exp $
27  */
28 
29 #include "zonenotify.h"
30 
main(int argc,char * argv[])31 int main(int argc, char *argv[])
32 {
33 	int i = 2;
34 	int ret = 0;
35 
36 	if (argc < 3) usage ();
37 
38 	while (i < argc) {
39 		if (init_connection (argv[i]) != -1) {
40 			if (slave_notify (argv[1], argv[i]) == -1) ret = 1;
41 			stop_connection ();
42 		} else
43 			fprintf (stderr, "Can't connect to %s\n", argv[i]);
44 		i++;
45 	}
46 
47 	exit (ret);
48 }
49 
usage()50 void usage ()
51 {
52 	printf ("%s, %s\n\nusage: zonenotify zone slave [slave 2 ... [slave n]] \n", VERSION, AUTHOR);
53 	printf ("where zone is the domain name to update on slave server ``slave''\n");
54 	exit (1);
55 }
56 
57 /* connect to the nameserver */
init_connection(const char * server)58 int init_connection (const char *server)
59 {
60 	struct	sockaddr_in sa, sl;
61 	struct	hostent *he;
62 	int	isbind = 0;
63 	int	i;
64 	long	rand;
65 	time_t	now;
66 
67 	time (&now);
68 	srandom ((long) now);
69 
70 	s = socket (AF_INET, SOCK_DGRAM, 0);
71 	if (s < 0) return -1;
72 
73 	/* local port: random */
74 	memset (&sl, 0, sizeof (sl));
75 	sl.sin_family = AF_INET;
76 	sl.sin_addr.s_addr = htonl (INADDR_ANY);
77 
78 	for (i = 0; i < 12 && !isbind; i++) {
79 		rand = 1025+(random () % 15000);
80 		sl.sin_port = htons (rand);
81 		isbind = (bind (s, (struct sockaddr *) &sl, sizeof (sl)) == 0);
82 	}
83 
84 	if (!isbind) return -1;
85 
86 	/* destination port: nameserver (53) */
87 	memset (&sa, 0, sizeof (sa));
88 	if (inet_aton (server, &sa.sin_addr) == 0) {
89 		he = gethostbyname (server);
90 
91 		if (he)
92 			memcpy (&sa.sin_addr, he->h_addr_list[0], sizeof (sa.sin_addr));
93 		else
94 			return -1;
95 	}
96 
97 	sa.sin_family = AF_INET;
98 	sa.sin_port = htons (NAMESERVER_PORT);
99 	if (connect (s, (struct sockaddr *) &sa, sizeof (sa)) != 0)
100 		return -1;
101 
102 	return 0;
103 }
104 
105 /* close local socket */
stop_connection(void)106 void stop_connection (void)
107 {
108 	shutdown (s, SHUT_RDWR);
109 }
110 
111 /* encode name string in ns query format */
ns_encode(char * str,char * buff)112 int ns_encode (char *str, char *buff)
113 {
114 	char *pos;
115 	int size;
116 	int len = 0;
117 
118 	while (1) {
119 		pos = (char *) strchr (str, '.');
120 
121 		if (!pos) break;
122 
123 		size = pos-str;
124 		*buff++ = size;
125 
126 		strncpy (buff, str, size);
127 		buff += size;
128 
129 		len += size+1;
130 		str = pos+1;
131 	}
132 
133 	size = strlen (str);
134 	if (size) {
135 		*buff++ = size;
136 		strncpy (buff, str, size);
137 		buff += size;
138 		len += size+1;
139 	}
140 
141 	*buff = 0;
142 
143 	return len;
144 }
145 
146 /* send sequest to our DNS-cache server */
slave_notify(char * domain,const char * server)147 int slave_notify (char *domain, const char *server)
148 {
149 	static int	unique = 0;
150 	char		buffer[PACKETSZ];
151 	char		name[MAXDNAME];
152 	HEADER		*hdr;
153 	int		len, reqlen;
154 	u_int16_t	val;
155 	fd_set		active_fd_set;
156 	struct timeval	tv_timeout;
157 
158 	hdr = (HEADER*) buffer;
159         hdr->qr = 0;
160         hdr->opcode = NS_NOTIFY_OP;
161         hdr->aa = 1;
162         hdr->tc = 0;
163         hdr->rd = 0;
164         hdr->ra = 0;
165         hdr->unused = 0;
166         hdr->rcode = 0;
167         hdr->qdcount = htons (1);
168         hdr->ancount = 0;
169         hdr->nscount = 0;
170         hdr->arcount = 0;
171         hdr->id = htons (unique++);
172 
173 	/* the 0x00 at the end must be copied! */
174 	reqlen = ns_encode (domain, name)+1;
175 	memcpy (buffer+sizeof (HEADER), name, reqlen);
176 
177 	/* query type */
178 	val = htons (T_SOA);
179 	memcpy (buffer+sizeof (HEADER)+reqlen, &val, 2);
180 	reqlen += 2;
181 
182 	/* query class */
183 	val = htons(C_IN);
184 	memcpy (buffer+sizeof (HEADER)+reqlen, &val, 2);
185 	reqlen += 2;
186 
187 	/* we wait max TIMEOUT seconds */
188 	tv_timeout.tv_sec = TIMEOUT;
189 	tv_timeout.tv_usec = 0;
190 
191 	FD_ZERO (&active_fd_set);
192 	FD_SET (s, &active_fd_set);
193 
194 	/* send the request to the nameserver */
195 	if (send (s, buffer, sizeof (HEADER)+reqlen, 0) == -1)
196 		return -1;
197 
198 	/* we wait the answere */
199 	if (select (FD_SETSIZE, &active_fd_set, NULL, NULL, &tv_timeout) < 1)
200 	{
201 		fprintf (stderr, "%s: timeout\n", server);
202 		return -1;
203 	}
204 
205 	/* and get back the answere */
206 	len = recv (s, buffer, PACKETSZ, 0);
207 	if (len != -1) {
208 		hdr = (HEADER*) buffer;
209 
210 		if (hdr->qr && hdr->rcode) {
211 			fprintf (stderr, "%s: %s\n",
212 					server,
213 					hdr->rcode < 23 ? dns_errors[hdr->rcode] : "unknow error");
214 			return -1;
215 		}
216 	}
217 
218 	return 0;
219 }
220