1 /* $OpenBSD: server.c,v 1.35 2009/05/20 14:55:59 henning 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 for (la = TAILQ_FIRST(&lconf->listen_addrs); la; ) { 79 switch (la->sa.ss_family) { 80 case AF_INET: 81 if (((struct sockaddr_in *)&la->sa)->sin_port == 0) 82 ((struct sockaddr_in *)&la->sa)->sin_port = 83 se->s_port; 84 break; 85 case AF_INET6: 86 if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0) 87 ((struct sockaddr_in6 *)&la->sa)->sin6_port = 88 se->s_port; 89 break; 90 default: 91 fatalx("king bula sez: af borked"); 92 } 93 94 log_info("listening on %s", 95 log_sockaddr((struct sockaddr *)&la->sa)); 96 97 if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1) 98 fatal("socket"); 99 100 if (la->sa.ss_family == AF_INET && setsockopt(la->fd, 101 IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) 102 log_warn("setsockopt IPTOS_LOWDELAY"); 103 104 if (bind(la->fd, (struct sockaddr *)&la->sa, 105 SA_LEN((struct sockaddr *)&la->sa)) == -1) { 106 struct listen_addr *nla; 107 108 log_warn("bind on %s failed, skipping", 109 log_sockaddr((struct sockaddr *)&la->sa)); 110 close(la->fd); 111 nla = TAILQ_NEXT(la, entry); 112 TAILQ_REMOVE(&lconf->listen_addrs, la, entry); 113 free(la); 114 la = nla; 115 continue; 116 } 117 new_cnt++; 118 la = TAILQ_NEXT(la, entry); 119 } 120 121 *cnt = new_cnt; 122 123 return (0); 124 } 125 126 int 127 server_dispatch(int fd, struct ntpd_conf *lconf) 128 { 129 ssize_t size; 130 u_int8_t version; 131 double rectime; 132 struct sockaddr_storage fsa; 133 socklen_t fsa_len; 134 struct ntp_msg query, reply; 135 char buf[NTP_MSGSIZE]; 136 137 fsa_len = sizeof(fsa); 138 if ((size = recvfrom(fd, &buf, sizeof(buf), 0, 139 (struct sockaddr *)&fsa, &fsa_len)) == -1) { 140 if (errno == EHOSTUNREACH || errno == EHOSTDOWN || 141 errno == ENETUNREACH || errno == ENETDOWN) { 142 log_warn("recvfrom %s", 143 log_sockaddr((struct sockaddr *)&fsa)); 144 return (0); 145 } else 146 fatal("recvfrom"); 147 } 148 149 rectime = gettime_corrected(); 150 151 if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1) 152 return (0); 153 154 version = (query.status & VERSIONMASK) >> 3; 155 156 bzero(&reply, sizeof(reply)); 157 if (lconf->status.synced) 158 reply.status = lconf->status.leap; 159 else 160 reply.status = LI_ALARM; 161 reply.status |= (query.status & VERSIONMASK); 162 if ((query.status & MODEMASK) == MODE_CLIENT) 163 reply.status |= MODE_SERVER; 164 else if ((query.status & MODEMASK) == MODE_SYM_ACT) 165 reply.status |= MODE_SYM_PAS; 166 else /* ignore packets of different type (e.g. bcast) */ 167 return (0); 168 169 reply.stratum = lconf->status.stratum; 170 reply.ppoll = query.ppoll; 171 reply.precision = lconf->status.precision; 172 reply.rectime = d_to_lfp(rectime); 173 reply.reftime = d_to_lfp(lconf->status.reftime); 174 reply.xmttime = d_to_lfp(gettime_corrected()); 175 reply.orgtime = query.xmttime; 176 reply.rootdelay = d_to_sfp(lconf->status.rootdelay); 177 reply.refid = lconf->status.refid; 178 179 ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0); 180 return (0); 181 } 182