]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/dnsmasq.c
import of dnsmasq-2.2.tar.gz
[people/ms/dnsmasq.git] / src / dnsmasq.c
CommitLineData
9e4abcb5
SK
1/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13/* See RFC1035 for details of the protocol this code talks. */
14
15/* Author's email: simon@thekelleys.org.uk */
16
17#include "dnsmasq.h"
18
19static int sigterm, sighup, sigusr1, sigusr2;
20
21static void sig_handler(int sig)
22{
23 if (sig == SIGTERM)
24 sigterm = 1;
25 else if (sig == SIGHUP)
26 sighup = 1;
27 else if (sig == SIGUSR1)
28 sigusr1 = 1;
29 else if (sig == SIGUSR2)
30 sigusr2 = 1;
31}
32
33int main (int argc, char **argv)
34{
35 char *int_err_string;
36 int cachesize = CACHESIZ;
37 int port = NAMESERVER_PORT;
38 int query_port = 0;
39 int first_loop = 1;
40 unsigned long local_ttl = 0;
41 unsigned int options;
42 char *runfile = RUNFILE;
43 time_t resolv_changed = 0;
44 time_t now, last = 0;
45 struct irec *iface, *interfaces = NULL;
46 char *mxname = NULL;
47 char *mxtarget = NULL;
48 char *lease_file = NULL;
49 char *addn_hosts = NULL;
50 char *domain_suffix = NULL;
51 char *username = CHUSER;
52 char *groupname = CHGRP;
53 struct iname *if_names = NULL;
54 struct iname *if_addrs = NULL;
55 struct iname *if_except = NULL;
56 struct iname *if_tmp;
57 struct server *serv_addrs = NULL;
58 char *dnamebuff, *packet;
59 struct server *servers, *last_server;
60 struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
61 struct resolvc *resolv = &default_resolv;
62 struct bogus_addr *bogus_addr = NULL;
63 struct serverfd *serverfdp, *sfds = NULL;
64 struct dhcp_context *dhcp_tmp, *dhcp = NULL;
65 struct dhcp_config *dhcp_configs = NULL;
66 struct dhcp_opt *dhcp_options = NULL;
67 char *dhcp_file = NULL, *dhcp_sname = NULL;
68 struct in_addr dhcp_next_server;
69 int leasefd = 0;
70 struct sigaction sigact;
71 sigset_t sigmask;
72
73 sighup = 1; /* init cache the first time through */
74 sigusr1 = 0; /* but don't dump */
75 sigusr2 = 0; /* or rescan interfaces */
76 sigterm = 0; /* or die */
77
78 sigact.sa_handler = sig_handler;
79 sigact.sa_flags = 0;
80 sigemptyset(&sigact.sa_mask);
81 sigaction(SIGUSR1, &sigact, NULL);
82 sigaction(SIGUSR2, &sigact, NULL);
83 sigaction(SIGHUP, &sigact, NULL);
84 sigaction(SIGTERM, &sigact, NULL);
85
86 /* now block all the signals, they stay that way except
87 during the call to pselect */
88 sigaddset(&sigact.sa_mask, SIGUSR1);
89 sigaddset(&sigact.sa_mask, SIGUSR2);
90 sigaddset(&sigact.sa_mask, SIGTERM);
91 sigaddset(&sigact.sa_mask, SIGHUP);
92 sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
93
94 /* These get allocated here to avoid overflowing the small stack
95 on embedded systems. dnamebuff is big enough to hold one
96 maximal sixed domain name and gets passed into all the processing
97 code. We manage to get away with one buffer. */
98 dnamebuff = safe_malloc(MAXDNAME);
99 /* Size: we check after adding each record, so there must be
100 memory for the largest packet, and the largest record */
101 packet = safe_malloc(PACKETSZ+MAXDNAME+RRFIXEDSZ);
102
103 dhcp_next_server.s_addr = 0;
104 options = read_opts(argc, argv, dnamebuff, &resolv, &mxname, &mxtarget, &lease_file,
105 &username, &groupname, &domain_suffix, &runfile,
106 &if_names, &if_addrs, &if_except, &bogus_addr,
107 &serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
108 &dhcp, &dhcp_configs, &dhcp_options,
109 &dhcp_file, &dhcp_sname, &dhcp_next_server);
110
111 if (!lease_file)
112 lease_file = LEASEFILE;
113 else
114 {
115 if (!dhcp)
116 {
117 complain("********* dhcp-lease option set, but not dhcp-range.", NULL);
118 complain("********* Are you trying to use the obsolete ISC dhcpd integration?", NULL);
119 complain("********* Please configure the dnsmasq integrated DHCP server by using", NULL);
120 complain("********* the \"dhcp-range\" option, and remove any other DHCP server.", NULL);
121 }
122 }
123
124 if ((int_err_string = enumerate_interfaces(&interfaces, if_names, if_addrs, if_except, dhcp, port)))
125 die(int_err_string, NULL);
126
127 for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
128 if (if_tmp->name && !if_tmp->found)
129 die("unknown interface %s", if_tmp->name);
130
131 for (if_tmp = if_addrs; if_tmp; if_tmp = if_tmp->next)
132 if (!if_tmp->found)
133 {
134#ifdef HAVE_IPV6
135 if (if_tmp->addr.sa.sa_family == AF_INET)
136 inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
137 dnamebuff, MAXDNAME);
138 else
139 inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
140 dnamebuff, MAXDNAME);
141 die("no interface with address %s", dnamebuff);
142#else
143 die("no interface with address %s", inet_ntoa(if_tmp->addr.in.sin_addr));
144#endif
145 }
146
147 forward_init(1);
148 cache_init(cachesize, options & OPT_LOG);
149
150 if (dhcp)
151 {
152
153#if !defined(HAVE_PF_PACKET) && !defined(HAVE_BPF)
154 die("no DHCP support available on this OS.", NULL);
155#endif
156
157 for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
158 if (!dhcp_tmp->iface)
159 die("No suitable interface for DHCP service at address %s", inet_ntoa(dhcp_tmp->start));
160
1ab84e2f 161 set_configs_from_cache(dhcp_configs);
9e4abcb5
SK
162 leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, time(NULL), dhcp_configs);
163 lease_update_dns(1); /* must follow cache_init and lease_init */
164 }
165
166 setbuf(stdout, NULL);
167
168 if (!(options & OPT_DEBUG))
169 {
170 FILE *pidfile;
171 struct passwd *ent_pw;
172 int i;
173
174 /* The following code "daemonizes" the process.
175 See Stevens section 12.4 */
176
177#ifndef NO_FORK
178 if (fork() != 0 )
179 exit(0);
180
181 setsid();
182
183 if (fork() != 0)
184 exit(0);
185#endif
186
187 chdir("/");
188 umask(022); /* make pidfile 0644 */
189
190 /* write pidfile _after_ forking ! */
191 if (runfile && (pidfile = fopen(runfile, "w")))
192 {
193 fprintf(pidfile, "%d\n", (int) getpid());
194 fclose(pidfile);
195 }
196
197 umask(0);
198
199 for (i=0; i<64; i++)
200 {
201 for (iface = interfaces; iface; iface = iface->next)
202 if (iface->fd == i)
203 break;
204 if (iface)
205 continue;
206
207 for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
208 if (dhcp_tmp->fd == i || dhcp_tmp->rawfd == i)
209 break;
210 if (dhcp_tmp)
211 continue;
212
213 if (dhcp && (i == leasefd))
214 continue;
215
216 close(i);
217 }
218
219 /* Change uid and gid for security */
220 if (username && (ent_pw = getpwnam(username)))
221 {
222 gid_t dummy;
223 struct group *gp;
224 /* remove all supplimentary groups */
225 setgroups(0, &dummy);
226 /* change group for /etc/ppp/resolv.conf
227 otherwise get the group for "nobody" */
228 if ((groupname && (gp = getgrnam(groupname))) ||
229 (gp = getgrgid(ent_pw->pw_gid)))
230 setgid(gp->gr_gid);
231 /* finally drop root */
232 setuid(ent_pw->pw_uid);
233 }
234 }
235
236 openlog("dnsmasq",
237 DNSMASQ_LOG_OPT(options & OPT_DEBUG),
238 DNSMASQ_LOG_FAC(options & OPT_DEBUG));
239
240 if (cachesize)
241 syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
242 else
243 syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
244
245 if (options & OPT_LOCALMX)
246 syslog(LOG_INFO, "serving MX record for local hosts target %s", mxtarget);
247 else if (mxname)
248 syslog(LOG_INFO, "serving MX record for mailhost %s target %s",
249 mxname, mxtarget);
250
251 for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
252 {
253 strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
254 if (dhcp_tmp->lease_time == 0)
255 sprintf(packet, "infinite");
256 else
257 sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
258 syslog(LOG_INFO, "DHCP on %s, IP range %s -- %s, lease time %s",
259 dhcp_tmp->iface, dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
260 }
261
262 if (getuid() == 0 || geteuid() == 0)
263 syslog(LOG_WARNING, "failed to drop root privs");
264
265 servers = last_server = check_servers(serv_addrs, interfaces, &sfds);
266
267 while (sigterm == 0)
268 {
269 fd_set rset;
270
271 if (sighup)
272 {
273 cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
1ab84e2f 274 set_configs_from_cache(dhcp_configs);
9e4abcb5
SK
275 lease_update_dns(1);
276 if (resolv && (options & OPT_NO_POLL))
277 servers = last_server =
278 check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
279 interfaces, &sfds);
280 sighup = 0;
281 }
282
283 if (sigusr1)
284 {
285 dump_cache(options & (OPT_DEBUG | OPT_LOG), cachesize);
286 sigusr1 = 0;
287 }
288
289 if (sigusr2)
290 {
291 if (getuid() != 0 && port <= 1024)
292 syslog(LOG_ERR, "cannot re-scan interfaces unless --user=root");
293 else
294 {
295 syslog(LOG_INFO, "rescanning network interfaces");
296 int_err_string = enumerate_interfaces(&interfaces, if_names, if_addrs, if_except, NULL, port);
297 if (int_err_string)
298 syslog(LOG_ERR, int_err_string, strerror(errno));
299 }
300 sigusr2 = 0;
301 }
302
303 FD_ZERO(&rset);
304
305 if (!first_loop)
306 {
307 int maxfd = 0;
308
309 for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
310 {
311 FD_SET(serverfdp->fd, &rset);
312 if (serverfdp->fd > maxfd)
313 maxfd = serverfdp->fd;
314 }
315
316 for (iface = interfaces; iface; iface = iface->next)
317 {
318 FD_SET(iface->fd, &rset);
319 if (iface->fd > maxfd)
320 maxfd = iface->fd;
321 }
322
323 for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
324 {
325 FD_SET(dhcp_tmp->fd, &rset);
326 if (dhcp_tmp->fd > maxfd)
327 maxfd = dhcp_tmp->fd;
328 }
329#ifdef HAVE_PSELECT
330 if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
331 FD_ZERO(&rset); /* rset otherwise undefined after error */
332#else
333 {
334 sigset_t save_mask;
335 sigprocmask(SIG_SETMASK, &sigmask, &save_mask);
336 if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)
337 FD_ZERO(&rset); /* rset otherwise undefined after error */
338 sigprocmask(SIG_SETMASK, &save_mask, NULL);
339 }
340#endif
341
342 }
343
344 first_loop = 0;
345 now = time(NULL);
346
347 /* Check for changes to resolv files once per second max. */
348 if (last == 0 || difftime(now, last) > 1.0)
349 {
350 last = now;
351 if (!(options & OPT_NO_POLL))
352 {
353 struct resolvc *res = resolv, *latest = NULL;
354 time_t last_change = 0;
355 struct stat statbuf;
356 /* There may be more than one possible file.
357 Go through and find the one which changed _last_.
358 Warn of any which can't be read. */
359 while (res)
360 {
361 if (stat(res->name, &statbuf) == -1)
362 {
363 if (!res->logged)
364 syslog(LOG_WARNING, "failed to access %s: %m", res->name);
365 res->logged = 1;
366 }
367 else
368 {
369 res->logged = 0;
370 if (statbuf.st_mtime > last_change)
371 {
372 last_change = statbuf.st_mtime;
373 latest = res;
374 }
375 }
376 res = res->next;
377 }
378
379 if (latest && last_change > resolv_changed)
380 {
381 resolv_changed = last_change;
382 servers = last_server =
383 check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
384 interfaces, &sfds);
385 }
386 }
387 }
388
389 for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
390 if (FD_ISSET(serverfdp->fd, &rset))
391 last_server = reply_query(serverfdp->fd, options, packet, now,
392 dnamebuff, last_server, bogus_addr);
393
394 for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
395 if (FD_ISSET(dhcp_tmp->fd, &rset))
396 dhcp_packet(dhcp_tmp, packet, dhcp_options, dhcp_configs,
397 now, dnamebuff, domain_suffix, dhcp_file,
398 dhcp_sname, dhcp_next_server);
399
400 for (iface = interfaces; iface; iface = iface->next)
401 {
402 if (FD_ISSET(iface->fd, &rset))
403 {
404 /* request packet, deal with query */
405 union mysockaddr udpaddr;
406 socklen_t udplen = sizeof(udpaddr);
407 HEADER *header = (HEADER *)packet;
408 int m, n = recvfrom(iface->fd, packet, PACKETSZ, 0, &udpaddr.sa, &udplen);
409 udpaddr.sa.sa_family = iface->addr.sa.sa_family;
410#ifdef HAVE_IPV6
411 if (udpaddr.sa.sa_family == AF_INET6)
412 udpaddr.in6.sin6_flowinfo = htonl(0);
413#endif
414 if (n >= (int)sizeof(HEADER) && !header->qr)
415 {
416 if (extract_request(header, (unsigned int)n, dnamebuff))
417 {
418 if (udpaddr.sa.sa_family == AF_INET)
419 log_query(F_QUERY | F_IPV4 | F_FORWARD, dnamebuff,
420 (struct all_addr *)&udpaddr.in.sin_addr);
421#ifdef HAVE_IPV6
422 else
423 log_query(F_QUERY | F_IPV6 | F_FORWARD, dnamebuff,
424 (struct all_addr *)&udpaddr.in6.sin6_addr);
425#endif
426 }
427
428 m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
429 mxname, mxtarget, options, now, local_ttl, dnamebuff);
430 if (m >= 1)
431 {
432 /* answered from cache, send reply */
433 sendto(iface->fd, (char *)header, m, 0,
434 &udpaddr.sa, sa_len(&udpaddr));
435 }
436 else
437 {
438 /* cannot answer from cache, send on to real nameserver */
439 last_server = forward_query(iface->fd, &udpaddr, header, n,
440 options, dnamebuff, servers,
441 last_server, now, local_ttl);
442 }
443 }
444
445 }
446 }
447 }
448
449 syslog(LOG_INFO, "exiting on receipt of SIGTERM");
450 return 0;
451}
452
453
454
455
456
457