1 /* 2 * Copyright (c) 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "defs.h" 36 37 static void usage(const char *av0); 38 static void dotest(const char *target); 39 static void add_server(const char *target); 40 static void process_config_file(const char *path); 41 static pid_t check_pid(void); 42 static void set_pid(const char *av0); 43 static void sigint_handler(int signo __unused); 44 45 static struct server_info **servers; 46 static int nservers; 47 static int maxservers; 48 49 int daemon_opt = 1; 50 int debug_opt = 0; 51 int debug_level = -1; /* (set to default later) */ 52 int quickset_opt = 0; /* immediately set time of day on startup */ 53 int no_update_opt = 0; /* do not make any actual updates */ 54 int min_sleep_opt = 5; /* 5 seconds minimum poll interval */ 55 int nom_sleep_opt = 300; /* 5 minutes nominal poll interval */ 56 int max_sleep_opt = 1800; /* 30 minutes maximum poll interval */ 57 int family = PF_UNSPEC; /* Address family */ 58 double insane_deviation = 0.5; /* 0.5 seconds of deviation == insane */ 59 const char *config_opt; /* config file */ 60 const char *pid_opt = "/var/run/dntpd.pid"; 61 62 int 63 main(int ac, char **av) 64 { 65 int test_opt = 0; 66 pid_t pid; 67 int ch; 68 int i; 69 70 /* 71 * Really randomize 72 */ 73 srandomdev(); 74 75 /* 76 * Process Options 77 */ 78 while ((ch = getopt(ac, av, "46df:i:l:np:qstFL:QST:")) != -1) { 79 switch(ch) { 80 case '4': 81 family = PF_INET; 82 break; 83 case '6': 84 family = PF_INET6; 85 break; 86 case 'd': 87 debug_opt = 1; 88 daemon_opt = 0; 89 if (debug_level < 0) 90 debug_level = 99; 91 if (config_opt == NULL) 92 config_opt = "/dev/null"; 93 break; 94 case 'p': 95 pid_opt = optarg; 96 break; 97 case 'f': 98 config_opt = optarg; 99 break; 100 case 'i': 101 insane_deviation = strtod(optarg, NULL); 102 break; 103 case 'l': 104 debug_level = strtol(optarg, NULL, 0); 105 break; 106 case 'n': 107 no_update_opt = 1; 108 break; 109 case 'q': 110 debug_level = 0; 111 break; 112 case 's': 113 quickset_opt = 1; 114 break; 115 case 'S': 116 quickset_opt = 0; 117 break; 118 case 't': 119 test_opt = 1; 120 debug_opt = 1; 121 daemon_opt = 0; 122 if (debug_level < 0) 123 debug_level = 99; 124 if (config_opt == NULL) 125 config_opt = "/dev/null"; 126 break; 127 case 'F': 128 daemon_opt = 0; 129 break; 130 case 'L': 131 max_sleep_opt = strtol(optarg, NULL, 0); 132 break; 133 case 'T': 134 nom_sleep_opt = strtol(optarg, NULL, 0); 135 if (nom_sleep_opt < 1) { 136 fprintf(stderr, "Warning: nominal poll interval too small, " 137 "limiting to 1 second\n"); 138 nom_sleep_opt = 1; 139 } 140 if (nom_sleep_opt > 24 * 60 * 60) { 141 fprintf(stderr, "Warning: nominal poll interval too large, " 142 "limiting to 24 hours\n"); 143 nom_sleep_opt = 24 * 60 * 60; 144 } 145 if (min_sleep_opt > nom_sleep_opt) 146 min_sleep_opt = nom_sleep_opt; 147 if (max_sleep_opt < nom_sleep_opt * 5) 148 max_sleep_opt = nom_sleep_opt * 5; 149 break; 150 case 'Q': 151 if ((pid = check_pid()) != 0) { 152 fprintf(stderr, "%s: killing old daemon\n", av[0]); 153 kill(pid, SIGINT); 154 usleep(100000); 155 if (check_pid()) 156 sleep(1); 157 if (check_pid()) 158 sleep(9); 159 if (check_pid()) { 160 fprintf(stderr, "%s: Unable to kill running daemon.\n", av[0]); 161 } else { 162 fprintf(stderr, "%s: Running daemon has been terminated.\n", av[0]); 163 } 164 } else { 165 fprintf(stderr, "%s: There is no daemon running to kill.\n", av[0]); 166 } 167 exit(0); 168 break; 169 case 'h': 170 default: 171 usage(av[0]); 172 /* not reached */ 173 } 174 } 175 176 /* 177 * Make sure min and nom intervals are less then or equal to the maximum 178 * interval. 179 */ 180 if (min_sleep_opt > max_sleep_opt) 181 min_sleep_opt = max_sleep_opt; 182 if (nom_sleep_opt > max_sleep_opt) 183 nom_sleep_opt = max_sleep_opt; 184 185 /* 186 * Set default config file 187 */ 188 if (config_opt == NULL) { 189 if (optind != ac) 190 config_opt = "/dev/null"; 191 else 192 config_opt = "/etc/dntpd.conf"; 193 } 194 195 if (debug_level < 0) 196 debug_level = 1; 197 198 process_config_file(config_opt); 199 200 if (debug_opt == 0) 201 openlog("dntpd", LOG_CONS|LOG_PID, LOG_DAEMON); 202 203 if (test_opt) { 204 if (optind != ac - 1) 205 usage(av[0]); 206 dotest(av[optind]); 207 /* not reached */ 208 } 209 210 /* 211 * Add additional hosts. 212 */ 213 for (i = optind; i < ac; ++i) { 214 add_server(av[i]); 215 } 216 if (nservers == 0) { 217 usage(av[0]); 218 /* not reached */ 219 } 220 221 /* 222 * Do an initial course time setting if requested using the first 223 * host successfully polled. 224 */ 225 /* XXX */ 226 227 /* 228 * Daemonize, stop logging to stderr. 229 */ 230 if (daemon_opt) { 231 if ((pid = check_pid()) != 0) { 232 logerrstr("%s: NOTE: killing old daemon and starting a new one", 233 av[0]); 234 kill(pid, SIGINT); 235 usleep(100000); 236 if (check_pid()) 237 sleep(1); 238 if (check_pid()) 239 sleep(9); 240 if (check_pid()) { 241 logerrstr("%s: Unable to kill running daemon, exiting", av[0]); 242 exit(1); 243 } 244 } 245 daemon(0, 0); 246 } else if (check_pid() != 0) { 247 logerrstr("%s: A background dntpd is running, you must kill it first", 248 av[0]); 249 exit(1); 250 } 251 if (debug_opt == 0) { 252 log_stderr = 0; 253 set_pid(av[0]); 254 signal(SIGINT, sigint_handler); 255 logdebug(0, "dntpd version %s started\n", DNTPD_VERSION); 256 } 257 258 /* 259 * And go. 260 */ 261 sysntp_clear_alternative_corrections(); 262 client_init(); 263 client_check_duplicate_ips(servers, nservers); 264 client_main(servers, nservers); 265 return(0); 266 } 267 268 static 269 void 270 usage(const char *av0) 271 { 272 fprintf(stderr, "%s [-dnqstFSQ] [-f config_file] [-l log_level] [-T poll_interval] [-L poll_limit] [additional_targets]\n", av0); 273 fprintf(stderr, 274 "\t-d\tDebugging mode, implies -F, -l 99, and logs to stderr\n" 275 "\t-f file\tSpecify the config file (/etc/dntpd.conf)\n" 276 "\t-l int\tSet log level (0-4), default 1\n" 277 "\t-n\tNo-update mode. No offset or frequency corrections are made\n" 278 "\t-q\tQuiet-mode, same as -L 0\n" 279 "\t-s\tSet the time immediately on startup\n" 280 "\t-t\tTest mode, implies -F, -l 99, -n, logs to stderr\n" 281 "\t-F\tRun in foreground (log still goes to syslog)\n" 282 "\t-L int\tMaximum polling interval\n" 283 "\t-S\tDo not set the time immediately on startup\n" 284 "\t-T int\tNominal polling interval\n" 285 "\t-Q\tTerminate any running background daemon\n" 286 "\n" 287 "\t\tNOTE: in debug and test modes -f must be specified if\n" 288 "\t\tyou want to use a config file.\n" 289 ); 290 exit(1); 291 } 292 293 static 294 void 295 dotest(const char *target) 296 { 297 struct server_info info; 298 299 bzero(&info, sizeof(info)); 300 info.sam = (struct sockaddr *)&info.sam_st; 301 info.fd = udp_socket(target, 123, info.sam, LOG_DNS_ERROR); 302 if (info.fd < 0) { 303 logerrstr("unable to create UDP socket for %s", target); 304 return; 305 } 306 info.target = strdup(target); 307 client_init(); 308 309 fprintf(stderr, 310 "Will run %d-second polls until interrupted.\n", nom_sleep_opt); 311 312 for (;;) { 313 client_poll(&info, nom_sleep_opt, 1); 314 sleep(nom_sleep_opt); 315 } 316 /* not reached */ 317 } 318 319 static char * 320 myaddr2ascii(struct sockaddr *sa) 321 { 322 static char str[INET6_ADDRSTRLEN]; 323 struct sockaddr_in *soin; 324 struct sockaddr_in6 *sin6; 325 326 switch (sa->sa_family) { 327 case AF_INET: 328 soin = (struct sockaddr_in *) sa; 329 inet_ntop(AF_INET, &soin->sin_addr, str, sizeof(str)); 330 break; 331 case AF_INET6: 332 sin6 = (struct sockaddr_in6 *) sa; 333 inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)); 334 break; 335 } 336 return (str); 337 } 338 339 static void 340 add_server(const char *target) 341 { 342 server_info_t info; 343 344 if (nservers == maxservers) { 345 maxservers += 16; 346 servers = realloc(servers, maxservers * sizeof(server_info_t)); 347 assert(servers != NULL); 348 } 349 info = malloc(sizeof(struct server_info)); 350 servers[nservers] = info; 351 bzero(info, sizeof(struct server_info)); 352 info->sam = (struct sockaddr *)&info->sam_st; 353 info->target = strdup(target); 354 /* 355 * Postpone socket opening and server name resolution until we are in main 356 * loop to avoid hang during init if network down. 357 */ 358 info->fd = -1; 359 info->server_state = -1; 360 ++nservers; 361 } 362 363 void 364 disconnect_server(server_info_t info) 365 { 366 if (info->fd >= 0) 367 close(info->fd); 368 info->fd = -1; 369 if (info->ipstr) { 370 free(info->ipstr); 371 info->ipstr = NULL; 372 } 373 } 374 375 void 376 reconnect_server(server_info_t info) 377 { 378 const char *ipstr; 379 dns_error_policy_t policy; 380 381 /* 382 * Ignore DNS errors if never connected before to handle the case where 383 * we're started before network up. 384 */ 385 policy = IGNORE_DNS_ERROR; 386 if (info->fd >= 0) { 387 close(info->fd); 388 policy = LOG_DNS_ERROR; 389 } 390 if (info->ipstr) { 391 free(info->ipstr); 392 info->ipstr = NULL; 393 } 394 info->sam = (struct sockaddr *)&info->sam_st; 395 info->fd = udp_socket(info->target, 123, info->sam, policy); 396 if (info->fd >= 0) { 397 ipstr = myaddr2ascii(info->sam); 398 info->ipstr = strdup(ipstr); 399 } 400 } 401 402 static void 403 process_config_file(const char *path) 404 { 405 const char *ws = " \t\r\n"; 406 char buf[1024]; 407 char *keyword; 408 char *data; 409 int line; 410 FILE *fi; 411 412 if ((fi = fopen(path, "r")) != NULL) { 413 line = 1; 414 while (fgets(buf, sizeof(buf), fi) != NULL) { 415 if (strchr(buf, '#')) 416 *strchr(buf, '#') = 0; 417 if ((keyword = strtok(buf, ws)) != NULL) { 418 data = strtok(NULL, ws); 419 if (strcmp(keyword, "server") == 0) { 420 if (data == NULL) { 421 logerr("%s:%d server missing host specification", 422 path, line); 423 } else { 424 add_server(data); 425 } 426 } else { 427 logerr("%s:%d unknown keyword %s", path, line, keyword); 428 } 429 } 430 ++line; 431 } 432 fclose(fi); 433 } else { 434 logerr("Unable to open %s", path); 435 exit(1); 436 } 437 } 438 439 static 440 pid_t 441 check_pid(void) 442 { 443 char buf[32]; 444 pid_t pid; 445 FILE *fi; 446 447 pid = 0; 448 if ((fi = fopen(pid_opt, "r")) != NULL) { 449 if (fgets(buf, sizeof(buf), fi) != NULL) { 450 pid = strtol(buf, NULL, 0); 451 if (kill(pid, 0) != 0) 452 pid = 0; 453 } 454 fclose(fi); 455 } 456 return(pid); 457 } 458 459 static 460 void 461 set_pid(const char *av0) 462 { 463 pid_t pid; 464 FILE *fo; 465 466 pid = getpid(); 467 if ((fo = fopen(pid_opt, "w")) != NULL) { 468 fprintf(fo, "%d\n", (int)pid); 469 fclose(fo); 470 } else { 471 logerr("%s: Unable to create %s, continuing anyway.", av0, pid_opt); 472 } 473 } 474 475 static 476 void 477 sigint_handler(int signo __unused) 478 { 479 remove(pid_opt); 480 /* dangerous, but we are exiting anyway so pray... */ 481 logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION); 482 exit(0); 483 } 484 485