1 /* $OpenBSD: server.c,v 1.32 2008/06/10 03:46:09 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2004 Alexander Guy <alexander@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <errno.h> 23 #include <ifaddrs.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "ntpd.h" 29 30 int 31 setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt) 32 { 33 struct listen_addr *la; 34 struct ifaddrs *ifa, *ifap; 35 struct sockaddr *sa; 36 u_int8_t *a6; 37 size_t sa6len = sizeof(struct in6_addr); 38 u_int new_cnt = 0; 39 int tos = IPTOS_LOWDELAY; 40 41 if (lconf->listen_all) { 42 if (getifaddrs(&ifa) == -1) 43 fatal("getifaddrs"); 44 45 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 46 sa = ifap->ifa_addr; 47 48 if (sa == NULL || 49 (sa->sa_family != AF_INET && 50 sa->sa_family != AF_INET6)) 51 continue; 52 if (SA_LEN(sa) == 0) 53 continue; 54 55 if (sa->sa_family == AF_INET && 56 ((struct sockaddr_in *)sa)->sin_addr.s_addr == 57 INADDR_ANY) 58 continue; 59 60 if (sa->sa_family == AF_INET6) { 61 a6 = ((struct sockaddr_in6 *)sa)-> 62 sin6_addr.s6_addr; 63 if (memcmp(a6, &in6addr_any, sa6len) == 0) 64 continue; 65 } 66 67 if ((la = calloc(1, sizeof(struct listen_addr))) == 68 NULL) 69 fatal("setup_listeners calloc"); 70 71 memcpy(&la->sa, sa, SA_LEN(sa)); 72 TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry); 73 } 74 75 freeifaddrs(ifa); 76 } 77 78 TAILQ_FOREACH(la, &lconf->listen_addrs, entry) { 79 new_cnt++; 80 81 switch (la->sa.ss_family) { 82 case AF_INET: 83 if (((struct sockaddr_in *)&la->sa)->sin_port == 0) 84 ((struct sockaddr_in *)&la->sa)->sin_port = 85 se->s_port; 86 break; 87 case AF_INET6: 88 if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0) 89 ((struct sockaddr_in6 *)&la->sa)->sin6_port = 90 se->s_port; 91 break; 92 default: 93 fatalx("king bula sez: af borked"); 94 } 95 96 log_info("listening on %s", 97 log_sockaddr((struct sockaddr *)&la->sa)); 98 99 if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1) 100 fatal("socket"); 101 102 if (la->sa.ss_family == AF_INET && setsockopt(la->fd, 103 IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) 104 log_warn("setsockopt IPTOS_LOWDELAY"); 105 106 if (bind(la->fd, (struct sockaddr *)&la->sa, 107 SA_LEN((struct sockaddr *)&la->sa)) == -1) 108 fatal("bind"); 109 } 110 111 *cnt = new_cnt; 112 113 return (0); 114 } 115 116 int 117 server_dispatch(int fd, struct ntpd_conf *lconf) 118 { 119 ssize_t size; 120 u_int8_t version; 121 double rectime; 122 struct sockaddr_storage fsa; 123 socklen_t fsa_len; 124 struct ntp_msg query, reply; 125 char buf[NTP_MSGSIZE]; 126 127 fsa_len = sizeof(fsa); 128 if ((size = recvfrom(fd, &buf, sizeof(buf), 0, 129 (struct sockaddr *)&fsa, &fsa_len)) == -1) { 130 if (errno == EHOSTUNREACH || errno == EHOSTDOWN || 131 errno == ENETUNREACH || errno == ENETDOWN) { 132 log_warn("recvfrom %s", 133 log_sockaddr((struct sockaddr *)&fsa)); 134 return (0); 135 } else 136 fatal("recvfrom"); 137 } 138 139 rectime = gettime_corrected(); 140 141 if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1) 142 return (0); 143 144 version = (query.status & VERSIONMASK) >> 3; 145 146 bzero(&reply, sizeof(reply)); 147 if (lconf->status.synced) 148 reply.status = lconf->status.leap; 149 else 150 reply.status = LI_ALARM; 151 reply.status |= (query.status & VERSIONMASK); 152 if ((query.status & MODEMASK) == MODE_CLIENT) 153 reply.status |= MODE_SERVER; 154 else 155 reply.status |= MODE_SYM_PAS; 156 157 reply.stratum = lconf->status.stratum; 158 reply.ppoll = query.ppoll; 159 reply.precision = lconf->status.precision; 160 reply.rectime = d_to_lfp(rectime); 161 reply.reftime = d_to_lfp(lconf->status.reftime); 162 reply.xmttime = d_to_lfp(gettime_corrected()); 163 reply.orgtime = query.xmttime; 164 reply.rootdelay = d_to_sfp(lconf->status.rootdelay); 165 reply.refid = lconf->status.refid; 166 167 ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0); 168 return (0); 169 } 170