Simon Kelley | f6b7dc4 | 2005-01-23 12:06:08 +0000 | [diff] [blame] | 1 | /* dnsmasq is Copyright (c) 2000-2005 Simon Kelley |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 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 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 13 | /* Author's email: simon@thekelleys.org.uk */ |
| 14 | |
| 15 | #include "dnsmasq.h" |
| 16 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 17 | static char *compile_opts = |
| 18 | #ifndef HAVE_IPV6 |
| 19 | "no-" |
| 20 | #endif |
| 21 | "IPv6 " |
| 22 | #ifndef HAVE_GETOPT_LONG |
| 23 | "no-" |
| 24 | #endif |
| 25 | "GNU-getopt " |
| 26 | #ifdef HAVE_BROKEN_RTC |
| 27 | "no-RTC " |
| 28 | #endif |
| 29 | #ifndef HAVE_ISC_READER |
| 30 | "no-" |
| 31 | #endif |
| 32 | "ISC-leasefile " |
| 33 | #ifndef HAVE_DBUS |
| 34 | "no-" |
| 35 | #endif |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 36 | "DBus " |
| 37 | #ifdef NO_GETTEXT |
| 38 | "no-" |
| 39 | #endif |
| 40 | "i18n"; |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 41 | |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 42 | static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 43 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 44 | static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd); |
| 45 | static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now); |
| 46 | static void sig_handler(int sig); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 47 | |
| 48 | int main (int argc, char **argv) |
| 49 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 50 | struct daemon *daemon; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 51 | int first_loop = 1; |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 52 | int bind_fallback = 0; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 53 | time_t now, last = 0; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 54 | struct sigaction sigact; |
| 55 | sigset_t sigmask; |
Simon Kelley | 26128d2 | 2004-11-14 16:43:54 +0000 | [diff] [blame] | 56 | struct iname *if_tmp; |
Simon Kelley | 33820b7 | 2004-04-03 21:10:00 +0100 | [diff] [blame] | 57 | |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 58 | #ifndef NO_GETTEXT |
| 59 | setlocale(LC_ALL, ""); |
| 60 | bindtextdomain("dnsmasq", LOCALEDIR); |
| 61 | textdomain("dnsmasq"); |
| 62 | #endif |
| 63 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 64 | sighup = 1; /* init cache the first time through */ |
| 65 | sigusr1 = 0; /* but don't dump */ |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 66 | sigterm = 0; /* or die */ |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 67 | #ifdef HAVE_BROKEN_RTC |
| 68 | sigalarm = 1; /* need regular lease dumps */ |
| 69 | #else |
| 70 | sigalarm = 0; /* or not */ |
| 71 | #endif |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 72 | num_kids = 0; |
| 73 | in_child = 0; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 74 | |
| 75 | sigact.sa_handler = sig_handler; |
| 76 | sigact.sa_flags = 0; |
| 77 | sigemptyset(&sigact.sa_mask); |
| 78 | sigaction(SIGUSR1, &sigact, NULL); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 79 | sigaction(SIGHUP, &sigact, NULL); |
| 80 | sigaction(SIGTERM, &sigact, NULL); |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 81 | sigaction(SIGALRM, &sigact, NULL); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 82 | sigaction(SIGCHLD, &sigact, NULL); |
| 83 | |
| 84 | /* ignore SIGPIPE */ |
| 85 | sigact.sa_handler = SIG_IGN; |
| 86 | sigaction(SIGPIPE, &sigact, NULL); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 87 | |
| 88 | /* now block all the signals, they stay that way except |
| 89 | during the call to pselect */ |
| 90 | sigaddset(&sigact.sa_mask, SIGUSR1); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 91 | sigaddset(&sigact.sa_mask, SIGTERM); |
| 92 | sigaddset(&sigact.sa_mask, SIGHUP); |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 93 | sigaddset(&sigact.sa_mask, SIGALRM); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 94 | sigaddset(&sigact.sa_mask, SIGCHLD); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 95 | sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask); |
| 96 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 97 | daemon = read_opts(argc, argv, compile_opts); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 98 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 99 | if (daemon->edns_pktsz < PACKETSZ) |
| 100 | daemon->edns_pktsz = PACKETSZ; |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 101 | daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ? |
| 102 | daemon->edns_pktsz : DNSMASQ_PACKETSZ; |
| 103 | daemon->packet = safe_malloc(daemon->packet_buff_sz); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 104 | |
| 105 | if (!daemon->lease_file) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 106 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 107 | if (daemon->dhcp) |
| 108 | daemon->lease_file = LEASEFILE; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 109 | } |
Simon Kelley | 33820b7 | 2004-04-03 21:10:00 +0100 | [diff] [blame] | 110 | #ifndef HAVE_ISC_READER |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 111 | else if (!daemon->dhcp) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 112 | die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL); |
Simon Kelley | 33820b7 | 2004-04-03 21:10:00 +0100 | [diff] [blame] | 113 | #endif |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 114 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 115 | if (!enumerate_interfaces(daemon, &daemon->interfaces, NULL, NULL)) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 116 | die(_("failed to find list of interfaces: %s"), NULL); |
Simon Kelley | f6b7dc4 | 2005-01-23 12:06:08 +0000 | [diff] [blame] | 117 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 118 | if (!(daemon->options & OPT_NOWILD) && |
| 119 | !(daemon->listeners = create_wildcard_listeners(daemon->port))) |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 120 | { |
| 121 | bind_fallback = 1; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 122 | daemon->options |= OPT_NOWILD; |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 123 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 124 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 125 | if (daemon->options & OPT_NOWILD) |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 126 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 127 | daemon->listeners = create_bound_listeners(daemon->interfaces, daemon->port); |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 128 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 129 | for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 130 | if (if_tmp->name && !if_tmp->used) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 131 | die(_("unknown interface %s"), if_tmp->name); |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 132 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 133 | for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next) |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 134 | if (!if_tmp->used) |
| 135 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 136 | prettyprint_addr(&if_tmp->addr, daemon->namebuff); |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 137 | die(_("no interface with address %s"), daemon->namebuff); |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 138 | } |
| 139 | } |
| 140 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 141 | forward_init(1); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 142 | cache_init(daemon->cachesize, daemon->options & OPT_LOG); |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 143 | |
| 144 | #ifdef HAVE_BROKEN_RTC |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 145 | if ((daemon->uptime_fd = open(UPTIME, O_RDONLY)) == -1) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 146 | die(_("cannot open %s:%s"), UPTIME); |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 147 | #endif |
| 148 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 149 | now = dnsmasq_time(daemon->uptime_fd); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 150 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 151 | if (daemon->dhcp) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 152 | { |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 153 | #if !defined(IP_PKTINFO) && !defined(IP_RECVIF) |
| 154 | int c; |
| 155 | struct iname *tmp; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 156 | for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next) |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 157 | if (!tmp->isloop) |
| 158 | c++; |
| 159 | if (c != 1) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 160 | die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL); |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 161 | #endif |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 162 | dhcp_init(daemon); |
| 163 | lease_init(daemon, now); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 164 | } |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 165 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 166 | if (daemon->options & OPT_DBUS) |
| 167 | #ifdef HAVE_DBUS |
| 168 | { |
| 169 | char *err; |
| 170 | daemon->dbus = NULL; |
| 171 | daemon->watches = NULL; |
| 172 | if ((err = dbus_init(daemon))) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 173 | die(_("DBus error: %s"), err); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 174 | } |
| 175 | #else |
| 176 | if (daemon->options & OPT_DBUS) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 177 | die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 178 | #endif |
| 179 | |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 180 | /* If query_port is set then create a socket now, before dumping root |
| 181 | for use to access nameservers without more specific source addresses. |
| 182 | This allows query_port to be a low port */ |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 183 | if (daemon->query_port) |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 184 | { |
| 185 | union mysockaddr addr; |
| 186 | addr.in.sin_family = AF_INET; |
| 187 | addr.in.sin_addr.s_addr = INADDR_ANY; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 188 | addr.in.sin_port = htons(daemon->query_port); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 189 | #ifdef HAVE_SOCKADDR_SA_LEN |
| 190 | addr.in.sin_len = sizeof(struct sockaddr_in); |
| 191 | #endif |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 192 | allocate_sfd(&addr, &daemon->sfds); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 193 | #ifdef HAVE_IPV6 |
| 194 | addr.in6.sin6_family = AF_INET6; |
| 195 | addr.in6.sin6_addr = in6addr_any; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 196 | addr.in6.sin6_port = htons(daemon->query_port); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 197 | addr.in6.sin6_flowinfo = htonl(0); |
| 198 | #ifdef HAVE_SOCKADDR_SA_LEN |
| 199 | addr.in6.sin6_len = sizeof(struct sockaddr_in6); |
| 200 | #endif |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 201 | allocate_sfd(&addr, &daemon->sfds); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 202 | #endif |
| 203 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 204 | |
| 205 | setbuf(stdout, NULL); |
| 206 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 207 | if (!(daemon->options & OPT_DEBUG)) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 208 | { |
| 209 | FILE *pidfile; |
| 210 | struct passwd *ent_pw; |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 211 | fd_set test_set; |
| 212 | int maxfd, i; |
| 213 | |
| 214 | FD_ZERO(&test_set); |
| 215 | maxfd = set_dns_listeners(daemon, &test_set, -1); |
| 216 | #ifdef HAVE_DBUS |
| 217 | maxfd = set_dbus_listeners(daemon, maxfd, &test_set, &test_set, &test_set); |
| 218 | #endif |
| 219 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 220 | /* The following code "daemonizes" the process. |
| 221 | See Stevens section 12.4 */ |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 222 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 223 | #ifndef NO_FORK |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 224 | if (!(daemon->options & OPT_NO_FORK)) |
| 225 | { |
| 226 | if (fork() != 0 ) |
| 227 | exit(0); |
| 228 | |
| 229 | setsid(); |
| 230 | |
| 231 | if (fork() != 0) |
| 232 | exit(0); |
| 233 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 234 | #endif |
| 235 | |
| 236 | chdir("/"); |
| 237 | umask(022); /* make pidfile 0644 */ |
| 238 | |
| 239 | /* write pidfile _after_ forking ! */ |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 240 | if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w"))) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 241 | { |
| 242 | fprintf(pidfile, "%d\n", (int) getpid()); |
| 243 | fclose(pidfile); |
| 244 | } |
| 245 | |
| 246 | umask(0); |
| 247 | |
| 248 | for (i=0; i<64; i++) |
| 249 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 250 | #ifdef HAVE_BROKEN_RTC |
| 251 | if (i == daemon->uptime_fd) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 252 | continue; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 253 | #endif |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 254 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 255 | if (daemon->dhcp && |
| 256 | (i == daemon->lease_fd || |
| 257 | i == daemon->dhcpfd || |
| 258 | i == daemon->dhcp_raw_fd || |
| 259 | i == daemon->dhcp_icmp_fd)) |
| 260 | continue; |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 261 | |
| 262 | if (i <= maxfd && FD_ISSET(i, &test_set)) |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 263 | continue; |
| 264 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 265 | close(i); |
| 266 | } |
| 267 | |
| 268 | /* Change uid and gid for security */ |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 269 | if (daemon->username && (ent_pw = getpwnam(daemon->username))) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 270 | { |
| 271 | gid_t dummy; |
| 272 | struct group *gp; |
| 273 | /* remove all supplimentary groups */ |
| 274 | setgroups(0, &dummy); |
| 275 | /* change group for /etc/ppp/resolv.conf |
| 276 | otherwise get the group for "nobody" */ |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 277 | if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) || |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 278 | (gp = getgrgid(ent_pw->pw_gid))) |
| 279 | setgid(gp->gr_gid); |
| 280 | /* finally drop root */ |
| 281 | setuid(ent_pw->pw_uid); |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | openlog("dnsmasq", |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 286 | DNSMASQ_LOG_OPT(daemon->options & OPT_DEBUG), |
| 287 | DNSMASQ_LOG_FAC(daemon->options & OPT_DEBUG)); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 288 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 289 | if (daemon->cachesize != 0) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 290 | syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 291 | else |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 292 | syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 293 | |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 294 | syslog(LOG_INFO, _("compile time options: %s"), compile_opts); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 295 | |
| 296 | #ifdef HAVE_DBUS |
| 297 | if (daemon->options & OPT_DBUS) |
| 298 | { |
| 299 | if (daemon->dbus) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 300 | syslog(LOG_INFO, _("DBus support enabled: connected to system bus")); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 301 | else |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 302 | syslog(LOG_INFO, _("DBus support enabled: bus connection pending")); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 303 | } |
| 304 | #endif |
| 305 | |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 306 | if (bind_fallback) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 307 | syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations")); |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 308 | |
Simon Kelley | 26128d2 | 2004-11-14 16:43:54 +0000 | [diff] [blame] | 309 | if (!(daemon->options & OPT_NOWILD)) |
| 310 | for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) |
| 311 | if (if_tmp->name && !if_tmp->used) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 312 | syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name); |
Simon Kelley | 26128d2 | 2004-11-14 16:43:54 +0000 | [diff] [blame] | 313 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 314 | if (daemon->dhcp) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 315 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 316 | struct dhcp_context *dhcp_tmp; |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 317 | |
| 318 | #ifdef HAVE_RTNETLINK |
| 319 | /* Must do this after daemonizing so that the pid is right */ |
| 320 | daemon->netlinkfd = netlink_init(); |
| 321 | #endif |
| 322 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 323 | for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next) |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 324 | { |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 325 | prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 326 | strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start)); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 327 | syslog(LOG_INFO, |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 328 | (dhcp_tmp->flags & CONTEXT_STATIC) ? |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 329 | _("DHCP, static leases only on %.0s%s, lease time %s") : |
| 330 | _("DHCP, IP range %s -- %s, lease time %s"), |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 331 | daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2); |
Simon Kelley | feba5c1 | 2004-07-27 20:28:58 +0100 | [diff] [blame] | 332 | } |
Simon Kelley | 26128d2 | 2004-11-14 16:43:54 +0000 | [diff] [blame] | 333 | |
| 334 | #ifdef HAVE_BROKEN_RTC |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 335 | daemon->min_leasetime = daemon->min_leasetime/3; |
| 336 | if (daemon->min_leasetime > (60 * 60 * 24)) |
| 337 | daemon->min_leasetime = 60 * 60 * 24; |
| 338 | if (daemon->min_leasetime < 60) |
| 339 | daemon->min_leasetime = 60; |
| 340 | prettyprint_time(daemon->dhcp_buff2, daemon->min_leasetime); |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 341 | syslog(LOG_INFO, _("DHCP, %s will be written every %s"), daemon->lease_file, daemon->dhcp_buff2); |
Simon Kelley | 26128d2 | 2004-11-14 16:43:54 +0000 | [diff] [blame] | 342 | #endif |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 343 | } |
| 344 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 345 | if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0)) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 346 | syslog(LOG_WARNING, _("running as root")); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 347 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 348 | check_servers(daemon); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 349 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 350 | while (sigterm == 0) |
| 351 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 352 | fd_set rset, wset, eset; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 353 | |
| 354 | if (sighup) |
| 355 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 356 | clear_cache_and_reload(daemon, now); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 357 | if (daemon->resolv_files && (daemon->options & OPT_NO_POLL)) |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 358 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 359 | reload_servers(daemon->resolv_files->name, daemon); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 360 | check_servers(daemon); |
Simon Kelley | de37951 | 2004-06-22 20:23:33 +0100 | [diff] [blame] | 361 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 362 | sighup = 0; |
| 363 | } |
| 364 | |
| 365 | if (sigusr1) |
| 366 | { |
Simon Kelley | fd9fa48 | 2004-10-21 20:24:00 +0100 | [diff] [blame] | 367 | dump_cache(daemon); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 368 | sigusr1 = 0; |
| 369 | } |
| 370 | |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 371 | if (sigalarm) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 372 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 373 | if (daemon->dhcp) |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 374 | { |
| 375 | lease_update_file(1, now); |
| 376 | #ifdef HAVE_BROKEN_RTC |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 377 | alarm(daemon->min_leasetime); |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 378 | #endif |
| 379 | } |
| 380 | sigalarm = 0; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 381 | } |
| 382 | |
| 383 | FD_ZERO(&rset); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 384 | FD_ZERO(&wset); |
| 385 | FD_ZERO(&eset); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 386 | |
| 387 | if (!first_loop) |
| 388 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 389 | int maxfd = set_dns_listeners(daemon, &rset, -1); |
| 390 | #ifdef HAVE_DBUS |
| 391 | maxfd = set_dbus_listeners(daemon, maxfd, &rset, &wset, &eset); |
| 392 | #endif |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 393 | if (daemon->dhcp) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 394 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 395 | FD_SET(daemon->dhcpfd, &rset); |
| 396 | if (daemon->dhcpfd > maxfd) |
| 397 | maxfd = daemon->dhcpfd; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 398 | } |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 399 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 400 | /* Whilst polling for the dbus, wake every quarter second */ |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 401 | #ifdef HAVE_PSELECT |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 402 | { |
| 403 | struct timespec *tp = NULL; |
| 404 | #ifdef HAVE_DBUS |
| 405 | struct timespec t; |
| 406 | if ((daemon->options & OPT_DBUS) && !daemon->dbus) |
| 407 | { |
| 408 | tp = &t; |
| 409 | tp->tv_sec = 0; |
| 410 | tp->tv_nsec = 250000000; |
| 411 | } |
| 412 | #endif |
| 413 | if (pselect(maxfd+1, &rset, &wset, &eset, tp, &sigmask) < 0) |
| 414 | { |
| 415 | /* otherwise undefined after error */ |
| 416 | FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); |
| 417 | } |
| 418 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 419 | #else |
| 420 | { |
| 421 | sigset_t save_mask; |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 422 | struct timeval *tp = NULL; |
| 423 | #ifdef HAVE_DBUS |
| 424 | struct timeval t; |
| 425 | if ((daemon->options & OPT_DBUS) && !daemon->dbus) |
| 426 | { |
| 427 | tp = &t; |
| 428 | tp->tv_sec = 0; |
| 429 | tp->tv_usec = 250000; |
| 430 | } |
| 431 | #endif |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 432 | sigprocmask(SIG_SETMASK, &sigmask, &save_mask); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 433 | if (select(maxfd+1, &rset, &wset, &eset, tp) < 0) |
| 434 | { |
| 435 | /* otherwise undefined after error */ |
| 436 | FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); |
| 437 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 438 | sigprocmask(SIG_SETMASK, &save_mask, NULL); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 439 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 440 | } |
| 441 | #endif |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 442 | } |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 443 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 444 | first_loop = 0; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 445 | now = dnsmasq_time(daemon->uptime_fd); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 446 | |
| 447 | /* Check for changes to resolv files once per second max. */ |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 448 | /* Don't go silent for long periods if the clock goes backwards. */ |
| 449 | if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < 1.0) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 450 | { |
| 451 | last = now; |
Simon Kelley | 33820b7 | 2004-04-03 21:10:00 +0100 | [diff] [blame] | 452 | |
| 453 | #ifdef HAVE_ISC_READER |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 454 | if (daemon->lease_file && !daemon->dhcp) |
Simon Kelley | fd9fa48 | 2004-10-21 20:24:00 +0100 | [diff] [blame] | 455 | load_dhcp(daemon, now); |
Simon Kelley | 33820b7 | 2004-04-03 21:10:00 +0100 | [diff] [blame] | 456 | #endif |
| 457 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 458 | if (!(daemon->options & OPT_NO_POLL)) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 459 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 460 | struct resolvc *res = daemon->resolv_files, *latest = NULL; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 461 | struct stat statbuf; |
Simon Kelley | 33820b7 | 2004-04-03 21:10:00 +0100 | [diff] [blame] | 462 | time_t last_change = 0; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 463 | /* There may be more than one possible file. |
| 464 | Go through and find the one which changed _last_. |
| 465 | Warn of any which can't be read. */ |
| 466 | while (res) |
| 467 | { |
| 468 | if (stat(res->name, &statbuf) == -1) |
| 469 | { |
| 470 | if (!res->logged) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 471 | syslog(LOG_WARNING, _("failed to access %s: %m"), res->name); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 472 | res->logged = 1; |
| 473 | } |
| 474 | else |
| 475 | { |
| 476 | res->logged = 0; |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 477 | if (statbuf.st_mtime != res->mtime) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 478 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 479 | res->mtime = statbuf.st_mtime; |
| 480 | if (difftime(res->mtime, last_change) > 0.0) |
| 481 | { |
| 482 | last_change = res->mtime; |
| 483 | latest = res; |
| 484 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 485 | } |
| 486 | } |
| 487 | res = res->next; |
| 488 | } |
| 489 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 490 | if (latest) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 491 | { |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 492 | reload_servers(latest->name, daemon); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 493 | check_servers(daemon); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 494 | } |
| 495 | } |
| 496 | } |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 497 | |
| 498 | #ifdef HAVE_DBUS |
| 499 | /* if we didn't create a DBus connection, retry now. */ |
| 500 | if ((daemon->options & OPT_DBUS) && !daemon->dbus) |
| 501 | { |
| 502 | char *err; |
| 503 | if ((err = dbus_init(daemon))) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 504 | syslog(LOG_WARNING, _("DBus error: %s"), err); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 505 | if (daemon->dbus) |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 506 | syslog(LOG_INFO, _("connected to system DBus")); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 507 | } |
| 508 | check_dbus_listeners(daemon, &rset, &wset, &eset); |
| 509 | #endif |
| 510 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 511 | check_dns_listeners(daemon, &rset, now); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 512 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 513 | if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset)) |
| 514 | dhcp_packet(daemon, now); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 515 | } |
| 516 | |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 517 | syslog(LOG_INFO, _("exiting on receipt of SIGTERM")); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 518 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 519 | if (daemon->dhcp) |
| 520 | { |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 521 | #ifdef HAVE_BROKEN_RTC |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 522 | lease_update_file(1, now); |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame] | 523 | #endif |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 524 | close(daemon->lease_fd); |
| 525 | } |
| 526 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 527 | return 0; |
| 528 | } |
| 529 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 530 | static void sig_handler(int sig) |
| 531 | { |
| 532 | if (sig == SIGTERM) |
| 533 | sigterm = 1; |
| 534 | else if (sig == SIGHUP) |
| 535 | sighup = 1; |
| 536 | else if (sig == SIGUSR1) |
| 537 | sigusr1 = 1; |
| 538 | else if (sig == SIGALRM) |
| 539 | { |
| 540 | /* alarm is used to kill children after a fixed time. */ |
| 541 | if (in_child) |
| 542 | exit(0); |
| 543 | else |
| 544 | sigalarm = 1; |
| 545 | } |
| 546 | else if (sig == SIGCHLD) |
| 547 | { |
| 548 | /* See Stevens 5.10 */ |
| 549 | |
| 550 | while (waitpid(-1, NULL, WNOHANG) > 0) |
| 551 | num_kids--; |
| 552 | } |
| 553 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 554 | |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 555 | |
| 556 | void clear_cache_and_reload(struct daemon *daemon, time_t now) |
| 557 | { |
| 558 | cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts); |
| 559 | if (daemon->dhcp) |
| 560 | { |
| 561 | if (daemon->options & OPT_ETHERS) |
| 562 | dhcp_read_ethers(daemon); |
| 563 | dhcp_update_configs(daemon->dhcp_conf); |
Simon Kelley | b8187c8 | 2005-11-26 21:46:27 +0000 | [diff] [blame^] | 564 | lease_update_from_configs(daemon); |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 565 | lease_update_file(0, now); |
| 566 | lease_update_dns(daemon); |
| 567 | } |
| 568 | } |
| 569 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 570 | static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd) |
| 571 | { |
| 572 | struct serverfd *serverfdp; |
| 573 | struct listener *listener; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 574 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 575 | for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) |
| 576 | { |
| 577 | FD_SET(serverfdp->fd, set); |
| 578 | if (serverfdp->fd > maxfd) |
| 579 | maxfd = serverfdp->fd; |
| 580 | } |
| 581 | |
| 582 | for (listener = daemon->listeners; listener; listener = listener->next) |
| 583 | { |
| 584 | FD_SET(listener->fd, set); |
| 585 | if (listener->fd > maxfd) |
| 586 | maxfd = listener->fd; |
| 587 | FD_SET(listener->tcpfd, set); |
| 588 | if (listener->tcpfd > maxfd) |
| 589 | maxfd = listener->tcpfd; |
| 590 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 591 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 592 | return maxfd; |
| 593 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 594 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 595 | static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now) |
| 596 | { |
| 597 | struct serverfd *serverfdp; |
| 598 | struct listener *listener; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 599 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 600 | for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) |
| 601 | if (FD_ISSET(serverfdp->fd, set)) |
| 602 | reply_query(serverfdp, daemon, now); |
| 603 | |
| 604 | for (listener = daemon->listeners; listener; listener = listener->next) |
| 605 | { |
| 606 | if (FD_ISSET(listener->fd, set)) |
| 607 | receive_query(listener, daemon, now); |
| 608 | |
| 609 | if (FD_ISSET(listener->tcpfd, set)) |
| 610 | { |
| 611 | int confd; |
Simon Kelley | f6b7dc4 | 2005-01-23 12:06:08 +0000 | [diff] [blame] | 612 | struct in_addr netmask, dst_addr_4; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 613 | |
| 614 | while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR); |
| 615 | |
| 616 | if (confd != -1) |
| 617 | { |
Simon Kelley | f6b7dc4 | 2005-01-23 12:06:08 +0000 | [diff] [blame] | 618 | union mysockaddr tcp_addr; |
| 619 | socklen_t tcp_len = sizeof(union mysockaddr); |
| 620 | |
| 621 | /* Check for allowed interfaces when binding the wildcard address: |
| 622 | we do this by looking for an interface with the same address as |
| 623 | the local address of the TCP connection, then looking to see if that's |
| 624 | an allowed interface. As a side effect, we get the netmask of the |
| 625 | interface too, for localisation. */ |
| 626 | |
| 627 | if ((num_kids >= MAX_PROCS) || |
| 628 | (!(daemon->options & OPT_NOWILD) && |
| 629 | (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1 || |
| 630 | !enumerate_interfaces(daemon, NULL, &tcp_addr, &netmask)))) |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 631 | close(confd); |
Simon Kelley | 59353a6 | 2004-11-21 19:34:28 +0000 | [diff] [blame] | 632 | #ifndef NO_FORK |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 633 | else if (!(daemon->options & OPT_DEBUG) && fork()) |
| 634 | { |
| 635 | num_kids++; |
| 636 | close(confd); |
| 637 | } |
Simon Kelley | 59353a6 | 2004-11-21 19:34:28 +0000 | [diff] [blame] | 638 | #endif |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 639 | else |
| 640 | { |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 641 | unsigned char *buff; |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 642 | struct server *s; |
| 643 | int flags; |
| 644 | |
| 645 | /* Arrange for SIGALARM after CHILD_LIFETIME seconds to |
| 646 | terminate the process. */ |
| 647 | if (!(daemon->options & OPT_DEBUG)) |
| 648 | { |
| 649 | sigset_t mask; |
| 650 | sigemptyset(&mask); |
| 651 | sigaddset(&mask, SIGALRM); |
| 652 | sigprocmask(SIG_UNBLOCK, &mask, NULL); |
| 653 | alarm(CHILD_LIFETIME); |
| 654 | in_child = 1; |
| 655 | } |
| 656 | |
| 657 | /* start with no upstream connections. */ |
| 658 | for (s = daemon->servers; s; s = s->next) |
| 659 | s->tcpfd = -1; |
| 660 | |
| 661 | /* The connected socket inherits non-blocking |
| 662 | attribute from the listening socket. |
| 663 | Reset that here. */ |
| 664 | if ((flags = fcntl(confd, F_GETFL, 0)) != -1) |
| 665 | fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); |
| 666 | |
Simon Kelley | f6b7dc4 | 2005-01-23 12:06:08 +0000 | [diff] [blame] | 667 | if (listener->family == AF_INET) |
| 668 | { |
| 669 | if (daemon->options & OPT_NOWILD) |
| 670 | { |
| 671 | netmask = listener->iface->netmask; |
| 672 | dst_addr_4 = listener->iface->addr.in.sin_addr; |
| 673 | } |
| 674 | else |
| 675 | /* netmask already set by enumerate_interfaces */ |
| 676 | dst_addr_4 = tcp_addr.in.sin_addr; |
| 677 | } |
| 678 | else |
| 679 | dst_addr_4.s_addr = 0; |
| 680 | |
| 681 | buff = tcp_request(daemon, confd, now, dst_addr_4, netmask); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 682 | |
| 683 | if (!(daemon->options & OPT_DEBUG)) |
| 684 | exit(0); |
| 685 | |
| 686 | close(confd); |
| 687 | if (buff) |
| 688 | free(buff); |
| 689 | for (s = daemon->servers; s; s = s->next) |
| 690 | if (s->tcpfd != -1) |
| 691 | close(s->tcpfd); |
| 692 | } |
| 693 | } |
| 694 | } |
| 695 | } |
| 696 | } |
| 697 | |
| 698 | int icmp_ping(struct daemon *daemon, struct in_addr addr) |
| 699 | { |
| 700 | /* Try and get an ICMP echo from a machine. |
| 701 | Note that we can't create the raw socket each time |
| 702 | we do this, since that needs root. Therefore the socket has to hang |
| 703 | around all the time. Since most of the time we won't read the |
| 704 | socket, it will accumulate buffers full of ICMP messages, |
| 705 | wasting memory. To avoid that we set the receive buffer |
| 706 | length to zero except when we're actively pinging. */ |
| 707 | |
| 708 | /* Note that whilst in the three second wait, we check for |
| 709 | (and service) events on the DNS sockets, (so doing that |
| 710 | better not use any resources our caller has in use...) |
| 711 | but we remain deaf to signals or further DHCP packets. */ |
| 712 | |
| 713 | struct sockaddr_in saddr; |
| 714 | struct { |
| 715 | struct ip ip; |
| 716 | struct icmp icmp; |
| 717 | } packet; |
| 718 | unsigned short id = rand16(); |
| 719 | unsigned int i, j; |
| 720 | int opt = 2000, gotreply = 0; |
| 721 | time_t start, now; |
| 722 | |
| 723 | saddr.sin_family = AF_INET; |
| 724 | saddr.sin_port = 0; |
| 725 | saddr.sin_addr = addr; |
| 726 | #ifdef HAVE_SOCKADDR_SA_LEN |
| 727 | saddr.sin_len = sizeof(struct sockaddr_in); |
| 728 | #endif |
| 729 | |
| 730 | memset(&packet.icmp, 0, sizeof(packet.icmp)); |
| 731 | packet.icmp.icmp_type = ICMP_ECHO; |
| 732 | packet.icmp.icmp_id = id; |
| 733 | for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++) |
| 734 | j += ((u16 *)&packet.icmp)[i]; |
| 735 | while (j>>16) |
| 736 | j = (j & 0xffff) + (j >> 16); |
| 737 | packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j; |
| 738 | |
| 739 | setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); |
| 740 | |
Simon Kelley | fd9fa48 | 2004-10-21 20:24:00 +0100 | [diff] [blame] | 741 | while (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0, |
| 742 | (struct sockaddr *)&saddr, sizeof(saddr)) == -1 && |
| 743 | retry_send()); |
| 744 | |
| 745 | for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;) |
| 746 | { |
| 747 | struct timeval tv; |
| 748 | fd_set rset; |
| 749 | struct sockaddr_in faddr; |
Simon Kelley | 3d8df26 | 2005-08-29 12:19:27 +0100 | [diff] [blame] | 750 | int maxfd; |
| 751 | socklen_t len = sizeof(faddr); |
Simon Kelley | fd9fa48 | 2004-10-21 20:24:00 +0100 | [diff] [blame] | 752 | |
| 753 | tv.tv_usec = 250000; |
| 754 | tv.tv_sec = 0; |
| 755 | |
| 756 | FD_ZERO(&rset); |
| 757 | FD_SET(daemon->dhcp_icmp_fd, &rset); |
| 758 | maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd); |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 759 | |
Simon Kelley | fd9fa48 | 2004-10-21 20:24:00 +0100 | [diff] [blame] | 760 | if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0) |
| 761 | FD_ZERO(&rset); |
| 762 | |
| 763 | now = dnsmasq_time(daemon->uptime_fd); |
| 764 | check_dns_listeners(daemon, &rset, now); |
| 765 | |
| 766 | if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) && |
| 767 | recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0, |
| 768 | (struct sockaddr *)&faddr, &len) == sizeof(packet) && |
| 769 | saddr.sin_addr.s_addr == faddr.sin_addr.s_addr && |
| 770 | packet.icmp.icmp_type == ICMP_ECHOREPLY && |
| 771 | packet.icmp.icmp_seq == 0 && |
| 772 | packet.icmp.icmp_id == id) |
| 773 | { |
| 774 | gotreply = 1; |
| 775 | break; |
| 776 | } |
| 777 | } |
| 778 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 779 | opt = 1; |
| 780 | setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); |
Simon Kelley | fd9fa48 | 2004-10-21 20:24:00 +0100 | [diff] [blame] | 781 | |
Simon Kelley | 3be3454 | 2004-09-11 19:12:13 +0100 | [diff] [blame] | 782 | return gotreply; |
| 783 | } |
Simon Kelley | 0a85254 | 2005-03-23 20:28:59 +0000 | [diff] [blame] | 784 | |
| 785 | |