1 /*
2 * common.c - includes global variables and functions.
3 *
4 * Copyright (C) 1998 Brad M. Garcia <garsh@home.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <sys/socket.h>
28 #include <sys/stat.h>
29 #include <signal.h>
30 #include <sys/types.h>
31 #include <stdlib.h>
32 #include <assert.h>
33 #include <string.h>
34 #include <errno.h>
35 #include "common.h"
36 #include "lib.h"
37 #include "dns.h"
38
39 #ifdef DEBUG
40 #define OPT_DEBUG 1
41 #else
42 #define OPT_DEBUG 0
43 #endif /* DEBUG */
44
45
46 /*
47 * These are all the global variables.
48 */
49 unsigned char
50 opt_debug = OPT_DEBUG;
51 int opt_serv = 0;
52 const char* progname = 0;
53
54 #ifdef ENABLE_PIDFILE
55 #if defined(__sun__)
56 const char* pid_file = "/var/tmp/dnrd.pid";
57 #else
58 const char* pid_file = "/var/run/dnrd.pid";
59 #endif
60 #endif
61
62 int isock = -1;
63 #ifdef ENABLE_TCP
64 int tcpsock = -1;
65 #endif
66 int select_timeout = SELECT_TIMEOUT;
67 int forward_timeout = FORWARD_TIMEOUT;
68 //int load_balance = 0;
69 #ifndef __CYGWIN__
70 uid_t daemonuid = 0;
71 gid_t daemongid = 0;
72 char dnrd_user[256] = "dnrd";
73 char dnrd_group[256] = "dnrd";
74 #endif
75 const char* version = PACKAGE_VERSION;
76 int gotterminal = 1; /* 1 if attached to a terminal */
77 sem_t dnrd_sem; /* Used for all thread synchronization */
78
79 int reactivate_interval = REACTIVATE_INTERVAL;
80 int stats_interval = 0;
81 int stats_reset = 1;
82
83 /* The path where we chroot. All config files are relative this path */
84 char dnrd_root[512] = DNRD_ROOT;
85
86 char config_file[512] = DNRD_ROOT "/" CONFIG_FILE;
87
88 domnode_t *domain_list;
89 /* turn this on to skip cache hits from responses of inactive dns servers */
90 int ignore_inactive_cache_hits = 0;
91
92 /* highest socket number */
93 int maxsock;
94
95 /* maximum number of open sockets. If we have this amount of
96 concurrent queries, we start dropping new ones */
97 int max_sockets = 200;
98
99 /* the fd set. query modifies this so we make it global */
100 fd_set fdmaster;
101
102
103
104 /*
105 * This is the address we listen on. It gets initialized to INADDR_ANY,
106 * which means we listen on all local addresses. Both the address and
107 * the port can be changed through command-line options.
108 */
109 /*
110 #if defined(__sun__)
111 struct sockaddr_in recv_addr = { AF_INET, 53, { { {0, 0, 0, 0} } } };
112 #else
113 struct sockaddr_in recv_addr = { AF_INET, 53, { INADDR_ANY } };
114 #endif
115 */
116
117 /* init recv_addr in main.c instead of here */
118 struct sockaddr_in recv_addr;
119
120 #ifdef ENABLE_PIDFILE
121 /* check if a pid is running
122 * from the unix faq
123 * http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC18
124 */
125
isrunning(int pid)126 int isrunning(int pid) {
127 if (kill(pid, 0) ) {
128 if (errno==EPERM) {
129 return 1;
130 } else return 0;
131 } else {
132 return 1;
133 }
134 }
135
136 /* wait_for_exit()
137 *
138 * In: pid - the process id to wait for
139 * timeout - maximum time to wait in 1/100 secs
140 *
141 * Returns: 1 if it died in before timeout
142 *
143 * Abstract: Check if a process is running and wait til it does not
144 */
wait_for_exit(int pid,int timeout)145 int wait_for_exit(int pid, int timeout) {
146 while (timeout--) {
147 if (! isrunning(pid)) return 1;
148 usleep(10000);
149 }
150 /* ouch... we timed out */
151 return 0;
152 }
153
154 /*
155 * kill_current()
156 *
157 * Returns: 1 if a currently running dnrd was found & killed, 0 otherwise.
158 *
159 * Abstract: This function sees if pid_file already exists and, if it does,
160 * will kill the current dnrd process and remove the file.
161 */
kill_current()162 int kill_current()
163 {
164 int pid;
165 int retn;
166 struct stat finfo;
167 FILE* filep;
168
169 if (stat(pid_file, &finfo) != 0) return 0;
170
171 filep = fopen(pid_file, "r");
172 if (!filep) {
173 log_msg(LOG_ERR, "%s: Can't open %s\n", progname, pid_file);
174 exit(-1);
175 }
176 if ((retn = (fscanf(filep, "%i%*s", &pid) == 1))) {
177 kill(pid, SIGTERM);
178 /* dnrd gets 4 seconds to die or we give up */
179 if (!wait_for_exit(pid, 400)) {
180 log_msg(LOG_ERR, "The dnrd process didn't die within 4 seconds");
181 }
182 }
183 fclose(filep);
184 unlink(pid_file);
185 return retn;
186 }
187 #endif /* ENABLE_PIDFILE*/
188
get_typestr(int type)189 const char *get_typestr(int type) {
190 static const char *EMERG = "EMERG: ";
191 static const char *ALERT = "ALERT: ";
192 static const char *CRIT = "CRIT: ";
193 static const char *ERR = "ERROR: ";
194 static const char *WARNING = "Warning: ";
195 static const char *NOTICE = "Notice: ";
196 static const char *INFO = "Info: ";
197 static const char *DEBUG = "Debug: ";
198 static const char *EMPTY = "";
199
200 switch (type) {
201 case LOG_EMERG: return EMERG;
202 case LOG_ALERT: return ALERT;
203 case LOG_CRIT: return CRIT;
204 case LOG_ERR: return ERR;
205 case LOG_WARNING: return WARNING;
206 case LOG_NOTICE: return NOTICE;
207 case LOG_INFO: return INFO;
208 case LOG_DEBUG: return DEBUG;
209 default: return EMPTY;
210 }
211 }
212
213
214 /*
215 * log_msg()
216 *
217 * In: type - a syslog priority
218 * fmt - a formatting string, ala printf.
219 * ... - other printf-style arguments.
220 *
221 * Sends a message to stdout or stderr if attached to a terminal, otherwise
222 * it sends a message to syslog.
223 */
log_msg(int type,const char * fmt,...)224 void log_msg(int type, const char *fmt, ...)
225 {
226 va_list ap;
227
228 va_start(ap, fmt);
229
230 if (gotterminal) {
231 fprintf(stderr, get_typestr(type));
232 vfprintf(stderr, fmt, ap);
233 if (fmt[strlen(fmt) - 1] != '\n') fprintf(stderr, "\n");
234 }
235 else {
236 vsyslog(type, fmt, ap);
237 }
238 va_end(ap);
239 }
240
241 /*
242 * log_debug()
243 *
244 * In: fmt - a formatting string, ala printf.
245 * ... - other printf-style arguments.
246 *
247 * Abstract: If debugging is turned on, this will send the message
248 * to syslog with LOG_DEBUG priority.
249 */
log_debug(int level,const char * fmt,...)250 void log_debug(int level, const char *fmt, ...)
251 {
252 va_list ap;
253
254 if (opt_debug < level) return;
255
256 va_start(ap, fmt);
257 if (gotterminal) {
258 fprintf(stderr, "Debug: ");
259 vfprintf(stderr, fmt, ap);
260 if (fmt[strlen(fmt) - 1] != '\n') fprintf(stderr, "\n");
261 }
262 else {
263 vsyslog(LOG_DEBUG, fmt, ap);
264 }
265 va_end(ap);
266 }
267
268 /*
269 * cleanexit()
270 *
271 * In: status - the exit code.
272 *
273 * Abstract: This closes our sockets, removes /var/run/dnrd.pid,
274 * and then calls exit.
275 */
cleanexit(int status)276 void cleanexit(int status)
277 {
278 /* int i;*/
279
280 /* Only let one process run this code) */
281 sem_wait(&dnrd_sem);
282
283 log_debug(1, "Shutting down...\n");
284 if (isock >= 0) close(isock);
285 #ifdef ENABLE_TCP
286 if (tcpsock >= 0) close(tcpsock);
287 #endif
288 /*
289 for (i = 0; i < serv_cnt; i++) {
290 close(dns_srv[i].sock);
291 }
292 */
293 destroy_domlist(domain_list);
294 exit(status);
295 }
296
297
298 /*
299 * log_err_exit()
300 *
301 * In: exitcode - the exitcode returned
302 * fmt - a formatting string, ala printf.
303 * ... - other printf-style arguments.
304 *
305 * Sends a message to log_msg, LOG_ERR and exit clean
306 */
log_err_exit(int exitcode,const char * fmt,...)307 void log_err_exit(int exitcode, const char *fmt, ...)
308 {
309 va_list ap;
310 va_start(ap, fmt);
311
312 if (gotterminal) {
313 fprintf(stderr, get_typestr(LOG_ERR));
314 vfprintf(stderr, fmt, ap);
315 if (fmt[strlen(fmt) - 1] != '\n') fprintf(stderr, "\n");
316 }
317 else {
318 vsyslog(LOG_ERR, fmt, ap);
319 }
320 va_end(ap);
321 cleanexit(exitcode);
322 }
323
324
325
326 /*
327 * make_cname()
328 *
329 * In: text - human readable domain name string
330 *
331 * Returns: Pointer to the allocated, filled in character string on success,
332 * NULL on failure.
333 *
334 * Abstract: converts the human-readable domain name to the DNS CNAME
335 * form, where each node has a length byte followed by the
336 * text characters, and ends in a null byte. The space for
337 * this new representation is allocated by this function.
338 */
make_cname(const char * text,const int maxlen)339 char* make_cname(const char *text, const int maxlen)
340 {
341 /* this kind of code can easily contain buffer overflow.
342 I have checked it and double checked it so I believe it does not.
343 Natanael */
344 const char *tptr = text;
345 const char *end = text;
346 char *cname = (char*)allocate(strnlen(text, maxlen) + 2);
347 char *cptr = cname;
348
349 while (*end != 0) {
350 size_t diff;
351 end = strchr(tptr, '.');
352 if (end == NULL) end = text + strnlen(text, maxlen);
353 if (end <= tptr) {
354 free(cname);
355 return NULL;
356 }
357 diff = end - tptr;
358 *cptr++ = diff;
359 memcpy(cptr, tptr, diff);
360 cptr += diff;
361 tptr = end + 1;
362 }
363 *cptr = 0;
364 assert((unsigned)(cptr - cname) == strnlen(text, maxlen) + 1);
365 return cname;
366 }
367
368 /* convert cname to ascii and return a static buffer */
369 /* this func must *never* be called with an incomming DNS
370 packet as input. Never. */
cname2asc(const char * cname)371 char *cname2asc(const char *cname) {
372 static char buf[256];
373 /* Note: we don't really check the size of the incomming cname. but
374 according to RFC 1035 a name must not be bigger than 255 octets.
375 */
376 if (cname)
377 snprintf_cname((char *)cname, strlen(cname), 0, buf, sizeof(buf));
378 else
379 strncpy(buf, "(default)", sizeof(buf));
380 return buf;
381 }
382