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