]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/dnsmasq.c
import of dnsmasq-2.3.tar.gz
[people/ms/dnsmasq.git] / src / dnsmasq.c
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
19 static int sigterm, sighup, sigusr1, sigalarm;
20
21 static 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 == SIGALRM)
30 sigalarm = 1;
31 }
32
33 int main (int argc, char **argv)
34 {
35 int cachesize = CACHESIZ;
36 int port = NAMESERVER_PORT;
37 int maxleases = MAXLEASES;
38 int query_port = 0;
39 int first_loop = 1;
40 unsigned long local_ttl = 0;
41 unsigned int options, min_leasetime;
42 char *runfile = RUNFILE;
43 time_t resolv_changed = 0;
44 time_t now, last = 0;
45 struct irec *interfaces = NULL;
46 struct listener *listener, *listeners;
47 char *mxname = NULL;
48 char *mxtarget = NULL;
49 char *lease_file = NULL;
50 char *addn_hosts = NULL;
51 char *domain_suffix = NULL;
52 char *username = CHUSER;
53 char *groupname = CHGRP;
54 struct iname *if_names = NULL;
55 struct iname *if_addrs = NULL;
56 struct iname *if_except = NULL;
57 struct server *serv_addrs = NULL;
58 char *dnamebuff, *packet;
59 int uptime_fd = -1;
60 struct server *servers, *last_server;
61 struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
62 struct resolvc *resolv = &default_resolv;
63 struct bogus_addr *bogus_addr = NULL;
64 struct serverfd *serverfdp, *sfds = NULL;
65 struct dhcp_context *dhcp_tmp, *dhcp = NULL;
66 struct dhcp_config *dhcp_configs = NULL;
67 struct dhcp_opt *dhcp_options = NULL;
68 char *dhcp_file = NULL, *dhcp_sname = NULL;
69 struct in_addr dhcp_next_server;
70 int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
71 struct sigaction sigact;
72 sigset_t sigmask;
73
74 sighup = 1; /* init cache the first time through */
75 sigusr1 = 0; /* but don't dump */
76 sigterm = 0; /* or die */
77 #ifdef HAVE_BROKEN_RTC
78 sigalarm = 1; /* need regular lease dumps */
79 #else
80 sigalarm = 0; /* or not */
81 #endif
82
83 sigact.sa_handler = sig_handler;
84 sigact.sa_flags = 0;
85 sigemptyset(&sigact.sa_mask);
86 sigaction(SIGUSR1, &sigact, NULL);
87 sigaction(SIGHUP, &sigact, NULL);
88 sigaction(SIGTERM, &sigact, NULL);
89 sigaction(SIGALRM, &sigact, NULL);
90
91 /* now block all the signals, they stay that way except
92 during the call to pselect */
93 sigaddset(&sigact.sa_mask, SIGUSR1);
94 sigaddset(&sigact.sa_mask, SIGTERM);
95 sigaddset(&sigact.sa_mask, SIGHUP);
96 sigaddset(&sigact.sa_mask, SIGALRM);
97 sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
98
99 /* These get allocated here to avoid overflowing the small stack
100 on embedded systems. dnamebuff is big enough to hold one
101 maximal sixed domain name and gets passed into all the processing
102 code. We manage to get away with one buffer. */
103 dnamebuff = safe_malloc(MAXDNAME);
104 packet = safe_malloc(DNSMASQ_PACKETSZ);
105
106 dhcp_next_server.s_addr = 0;
107 options = read_opts(argc, argv, dnamebuff, &resolv, &mxname, &mxtarget, &lease_file,
108 &username, &groupname, &domain_suffix, &runfile,
109 &if_names, &if_addrs, &if_except, &bogus_addr,
110 &serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
111 &dhcp, &dhcp_configs, &dhcp_options,
112 &dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime);
113
114 /* if we cannot support binding the wildcard address, set the "bind only
115 interfaces in use" option */
116 #ifndef HAVE_UDP_SRC_DST
117 options |= OPT_NOWILD;
118 #endif
119
120 if (!lease_file)
121 lease_file = LEASEFILE;
122 else
123 {
124 if (!dhcp)
125 {
126 complain("********* dhcp-lease option set, but not dhcp-range.", NULL);
127 complain("********* Are you trying to use the obsolete ISC dhcpd integration?", NULL);
128 complain("********* Please configure the dnsmasq integrated DHCP server by using", NULL);
129 complain("********* the \"dhcp-range\" option, and remove any other DHCP server.", NULL);
130 }
131 }
132
133 interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
134 if (options & OPT_NOWILD)
135 listeners = create_bound_listeners(interfaces);
136 else
137 listeners = create_wildcard_listeners(port);
138
139 forward_init(1);
140 cache_init(cachesize, options & OPT_LOG);
141
142 #ifdef HAVE_BROKEN_RTC
143 if ((uptime_fd = open(UPTIME, O_RDONLY)) == -1)
144 die("cannot open " UPTIME ":%s", NULL);
145 #endif
146
147 now = dnsmasq_time(uptime_fd);
148
149 if (dhcp)
150 {
151 dhcp_init(&dhcpfd, &dhcp_raw_fd);
152 leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
153 if (options & OPT_ETHERS)
154 dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
155 dhcp_update_configs(dhcp_configs);
156 lease_update_from_configs(dhcp_configs, domain_suffix); /* must follow cache_init and lease_init */
157 lease_update_file(0, now);
158 lease_update_dns();
159 }
160
161 setbuf(stdout, NULL);
162
163 if (!(options & OPT_DEBUG))
164 {
165 FILE *pidfile;
166 struct passwd *ent_pw;
167 int i;
168
169 /* The following code "daemonizes" the process.
170 See Stevens section 12.4 */
171
172 #ifndef NO_FORK
173 if (fork() != 0 )
174 exit(0);
175
176 setsid();
177
178 if (fork() != 0)
179 exit(0);
180 #endif
181
182 chdir("/");
183 umask(022); /* make pidfile 0644 */
184
185 /* write pidfile _after_ forking ! */
186 if (runfile && (pidfile = fopen(runfile, "w")))
187 {
188 fprintf(pidfile, "%d\n", (int) getpid());
189 fclose(pidfile);
190 }
191
192 umask(0);
193
194 for (i=0; i<64; i++)
195 {
196 for (listener = listeners; listener; listener = listener->next)
197 if (listener->fd == i)
198 break;
199 if (listener)
200 continue;
201
202 if (i == leasefd ||
203 i == uptime_fd ||
204 i == dhcpfd ||
205 i == dhcp_raw_fd)
206 continue;
207
208 close(i);
209 }
210
211 /* Change uid and gid for security */
212 if (username && (ent_pw = getpwnam(username)))
213 {
214 gid_t dummy;
215 struct group *gp;
216 /* remove all supplimentary groups */
217 setgroups(0, &dummy);
218 /* change group for /etc/ppp/resolv.conf
219 otherwise get the group for "nobody" */
220 if ((groupname && (gp = getgrnam(groupname))) ||
221 (gp = getgrgid(ent_pw->pw_gid)))
222 setgid(gp->gr_gid);
223 /* finally drop root */
224 setuid(ent_pw->pw_uid);
225 }
226 }
227
228 openlog("dnsmasq",
229 DNSMASQ_LOG_OPT(options & OPT_DEBUG),
230 DNSMASQ_LOG_FAC(options & OPT_DEBUG));
231
232 if (cachesize)
233 syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
234 else
235 syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
236
237 if (options & OPT_LOCALMX)
238 syslog(LOG_INFO, "serving MX record for local hosts target %s", mxtarget);
239 else if (mxname)
240 syslog(LOG_INFO, "serving MX record for mailhost %s target %s",
241 mxname, mxtarget);
242
243 for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
244 {
245 strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
246 if (dhcp_tmp->lease_time == 0)
247 sprintf(packet, "infinite");
248 else
249 sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
250 syslog(LOG_INFO, "DHCP, IP range %s -- %s, lease time %s",
251 dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
252 }
253
254 #ifdef HAVE_BROKEN_RTC
255 if (dhcp)
256 syslog(LOG_INFO, "DHCP, %s will be written every %ds", lease_file, min_leasetime/3);
257 #endif
258
259 if (getuid() == 0 || geteuid() == 0)
260 syslog(LOG_WARNING, "failed to drop root privs");
261
262 servers = last_server = check_servers(serv_addrs, interfaces, &sfds);
263
264 while (sigterm == 0)
265 {
266 fd_set rset;
267
268 if (sighup)
269 {
270 cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
271 if (dhcp)
272 {
273 dhcp_update_configs(dhcp_configs);
274 lease_update_from_configs(dhcp_configs, domain_suffix);
275 lease_update_file(0, now);
276 lease_update_dns();
277 }
278 if (resolv && (options & OPT_NO_POLL))
279 servers = last_server =
280 check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
281 interfaces, &sfds);
282 sighup = 0;
283 }
284
285 if (sigusr1)
286 {
287 dump_cache(options & (OPT_DEBUG | OPT_LOG), cachesize);
288 sigusr1 = 0;
289 }
290
291 if (sigalarm)
292 {
293 if (dhcp)
294 {
295 lease_update_file(1, now);
296 #ifdef HAVE_BROKEN_RTC
297 alarm(min_leasetime/3);
298 #endif
299 }
300 sigalarm = 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 (listener = listeners; listener; listener = listener->next)
317 {
318 FD_SET(listener->fd, &rset);
319 if (listener->fd > maxfd)
320 maxfd = listener->fd;
321 }
322
323 if (dhcp)
324 {
325 FD_SET(dhcpfd, &rset);
326 if (dhcpfd > maxfd)
327 maxfd = dhcpfd;
328 }
329
330 #ifdef HAVE_PSELECT
331 if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
332 FD_ZERO(&rset); /* rset otherwise undefined after error */
333 #else
334 {
335 sigset_t save_mask;
336 sigprocmask(SIG_SETMASK, &sigmask, &save_mask);
337 if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)
338 FD_ZERO(&rset); /* rset otherwise undefined after error */
339 sigprocmask(SIG_SETMASK, &save_mask, NULL);
340 }
341 #endif
342
343 }
344
345 first_loop = 0;
346 now = dnsmasq_time(uptime_fd);
347
348 /* Check for changes to resolv files once per second max. */
349 if (last == 0 || difftime(now, last) > 1.0)
350 {
351 last = now;
352 if (!(options & OPT_NO_POLL))
353 {
354 struct resolvc *res = resolv, *latest = NULL;
355 time_t last_change = 0;
356 struct stat statbuf;
357 /* There may be more than one possible file.
358 Go through and find the one which changed _last_.
359 Warn of any which can't be read. */
360 while (res)
361 {
362 if (stat(res->name, &statbuf) == -1)
363 {
364 if (!res->logged)
365 syslog(LOG_WARNING, "failed to access %s: %m", res->name);
366 res->logged = 1;
367 }
368 else
369 {
370 res->logged = 0;
371 if (statbuf.st_mtime > last_change)
372 {
373 last_change = statbuf.st_mtime;
374 latest = res;
375 }
376 }
377 res = res->next;
378 }
379
380 if (latest && last_change > resolv_changed)
381 {
382 resolv_changed = last_change;
383 servers = last_server =
384 check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
385 interfaces, &sfds);
386 }
387 }
388 }
389
390 for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
391 if (FD_ISSET(serverfdp->fd, &rset))
392 last_server = reply_query(serverfdp->fd, options, packet, now,
393 dnamebuff, last_server, bogus_addr);
394
395 if (dhcp && FD_ISSET(dhcpfd, &rset))
396 dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs,
397 now, dnamebuff, domain_suffix, dhcp_file,
398 dhcp_sname, dhcp_next_server, dhcpfd, dhcp_raw_fd,
399 if_names, if_addrs, if_except);
400
401 for (listener = listeners; listener; listener = listener->next)
402 if (FD_ISSET(listener->fd, &rset))
403 last_server = receive_query(listener, packet,
404 mxname, mxtarget, options, now, local_ttl, dnamebuff,
405 if_names, if_addrs, if_except, last_server, servers);
406 }
407
408 syslog(LOG_INFO, "exiting on receipt of SIGTERM");
409
410 #ifdef HAVE_BROKEN_RTC
411 if (dhcp)
412 lease_update_file(1, now);
413 #endif
414
415 if (leasefd != -1)
416 close(leasefd);
417 return 0;
418 }
419
420
421
422
423
424