1/* $OpenBSD: server.c,v 1.44 2016/09/03 11:52:06 reyk 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 USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#include <sys/types.h> 21#include <sys/ioctl.h> 22#include <sys/socket.h> 23#include <net/if.h> 24#include <errno.h> 25#include <ifaddrs.h> 26#include <stdlib.h> 27#include <string.h> 28#include <unistd.h> 29 30#include "ntpd.h" 31 32int 33setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt) 34{ 35 struct listen_addr *la, *nla, *lap; 36 struct ifaddrs *ifa, *ifap; 37 struct sockaddr *sa; 38 struct if_data *ifd; 39 u_int8_t *a6; 40 size_t sa6len = sizeof(struct in6_addr); 41 u_int new_cnt = 0; 42 int tos = IPTOS_LOWDELAY, rdomain = 0; 43 44 TAILQ_FOREACH(lap, &lconf->listen_addrs, entry) { 45 switch (lap->sa.ss_family) { 46 case AF_UNSPEC: 47 if (getifaddrs(&ifa) == -1) 48 fatal("getifaddrs"); 49 50 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 51 sa = ifap->ifa_addr; 52 if (sa == NULL || SA_LEN(sa) == 0) 53 continue; 54 if (sa->sa_family == AF_LINK) { 55 ifd = ifap->ifa_data; 56 rdomain = ifd->ifi_rdomain; 57 } 58 if (sa->sa_family != AF_INET && 59 sa->sa_family != AF_INET6) 60 continue; 61 if (lap->rtable != -1 && rdomain != lap->rtable) 62 continue; 63 64 if (sa->sa_family == AF_INET && 65 ((struct sockaddr_in *)sa)->sin_addr.s_addr == 66 INADDR_ANY) 67 continue; 68 69 if (sa->sa_family == AF_INET6) { 70 a6 = ((struct sockaddr_in6 *)sa)-> 71 sin6_addr.s6_addr; 72 if (memcmp(a6, &in6addr_any, sa6len) == 0) 73 continue; 74 } 75 76 if ((la = calloc(1, sizeof(struct listen_addr))) == 77 NULL) 78 fatal("setup_listeners calloc"); 79 80 memcpy(&la->sa, sa, SA_LEN(sa)); 81 la->rtable = rdomain; 82 83 TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry); 84 } 85 86 freeifaddrs(ifa); 87 default: 88 continue; 89 } 90 } 91 92 93 for (la = TAILQ_FIRST(&lconf->listen_addrs); la; ) { 94 switch (la->sa.ss_family) { 95 case AF_INET: 96 if (((struct sockaddr_in *)&la->sa)->sin_port == 0) 97 ((struct sockaddr_in *)&la->sa)->sin_port = 98 se->s_port; 99 break; 100 case AF_INET6: 101 if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0) 102 ((struct sockaddr_in6 *)&la->sa)->sin6_port = 103 se->s_port; 104 break; 105 case AF_UNSPEC: 106 nla = TAILQ_NEXT(la, entry); 107 TAILQ_REMOVE(&lconf->listen_addrs, la, entry); 108 free(la); 109 la = nla; 110 continue; 111 default: 112 fatalx("king bula sez: af borked"); 113 } 114 115 log_info("listening on %s %s", 116 log_sockaddr((struct sockaddr *)&la->sa), 117 print_rtable(la->rtable)); 118 119 if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1) 120 fatal("socket"); 121 122 if (la->sa.ss_family == AF_INET && setsockopt(la->fd, 123 IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) 124 log_warn("setsockopt IPTOS_LOWDELAY"); 125 126 if (la->rtable != -1 && 127 setsockopt(la->fd, SOL_SOCKET, SO_RTABLE, &la->rtable, 128 sizeof(la->rtable)) == -1) 129 fatal("setup_listeners setsockopt SO_RTABLE"); 130 131 if (bind(la->fd, (struct sockaddr *)&la->sa, 132 SA_LEN((struct sockaddr *)&la->sa)) == -1) { 133 log_warn("bind on %s failed, skipping", 134 log_sockaddr((struct sockaddr *)&la->sa)); 135 close(la->fd); 136 nla = TAILQ_NEXT(la, entry); 137 TAILQ_REMOVE(&lconf->listen_addrs, la, entry); 138 free(la); 139 la = nla; 140 continue; 141 } 142 new_cnt++; 143 la = TAILQ_NEXT(la, entry); 144 } 145 146 *cnt = new_cnt; 147 148 return (0); 149} 150 151int 152server_dispatch(int fd, struct ntpd_conf *lconf) 153{ 154 ssize_t size; 155 double rectime; 156 struct sockaddr_storage fsa; 157 socklen_t fsa_len; 158 struct ntp_msg query, reply; 159 char buf[NTP_MSGSIZE]; 160 161 fsa_len = sizeof(fsa); 162 if ((size = recvfrom(fd, &buf, sizeof(buf), 0, 163 (struct sockaddr *)&fsa, &fsa_len)) == -1) { 164 if (errno == EHOSTUNREACH || errno == EHOSTDOWN || 165 errno == ENETUNREACH || errno == ENETDOWN) { 166 log_warn("recvfrom %s", 167 log_sockaddr((struct sockaddr *)&fsa)); 168 return (0); 169 } else 170 fatal("recvfrom"); 171 } 172 173 rectime = gettime_corrected(); 174 175 if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1) 176 return (0); 177 178 memset(&reply, 0, sizeof(reply)); 179 if (lconf->status.synced) 180 reply.status = lconf->status.leap; 181 else 182 reply.status = LI_ALARM; 183 reply.status |= (query.status & VERSIONMASK); 184 if ((query.status & MODEMASK) == MODE_CLIENT) 185 reply.status |= MODE_SERVER; 186 else if ((query.status & MODEMASK) == MODE_SYM_ACT) 187 reply.status |= MODE_SYM_PAS; 188 else /* ignore packets of different type (e.g. bcast) */ 189 return (0); 190 191 reply.stratum = lconf->status.stratum; 192 reply.ppoll = query.ppoll; 193 reply.precision = lconf->status.precision; 194 reply.rectime = d_to_lfp(rectime); 195 reply.reftime = d_to_lfp(lconf->status.reftime); 196 reply.xmttime = d_to_lfp(gettime_corrected()); 197 reply.orgtime = query.xmttime; 198 reply.rootdelay = d_to_sfp(lconf->status.rootdelay); 199 reply.refid = lconf->status.refid; 200 201 ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply); 202 return (0); 203} 204