xref: /openbsd-src/usr.sbin/ntpd/server.c (revision 774da4d1ccc43e2a4200d81b656c10f05a30b4b9)
1*774da4d1Sreyk /*	$OpenBSD: server.c,v 1.44 2016/09/03 11:52:06 reyk Exp $ */
26a5eeebaShenning 
36a5eeebaShenning /*
46a5eeebaShenning  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5d1204a71Salexander  * Copyright (c) 2004 Alexander Guy <alexander@openbsd.org>
66a5eeebaShenning  *
76a5eeebaShenning  * Permission to use, copy, modify, and distribute this software for any
86a5eeebaShenning  * purpose with or without fee is hereby granted, provided that the above
96a5eeebaShenning  * copyright notice and this permission notice appear in all copies.
106a5eeebaShenning  *
116a5eeebaShenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
126a5eeebaShenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
136a5eeebaShenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
146a5eeebaShenning  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*774da4d1Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*774da4d1Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*774da4d1Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
186a5eeebaShenning  */
196a5eeebaShenning 
20507aab02Salexander #include <sys/types.h>
2161f07045Sderaadt #include <sys/ioctl.h>
22507aab02Salexander #include <sys/socket.h>
2302d74365Sphessler #include <net/if.h>
246a5eeebaShenning #include <errno.h>
25507aab02Salexander #include <ifaddrs.h>
266a5eeebaShenning #include <stdlib.h>
276a5eeebaShenning #include <string.h>
286a5eeebaShenning #include <unistd.h>
296a5eeebaShenning 
306a5eeebaShenning #include "ntpd.h"
316a5eeebaShenning 
326a5eeebaShenning int
setup_listeners(struct servent * se,struct ntpd_conf * lconf,u_int * cnt)3396f46bd6Sotto setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt)
346a5eeebaShenning {
3502d74365Sphessler 	struct listen_addr	*la, *nla, *lap;
364b8145c3Sdtucker 	struct ifaddrs		*ifa, *ifap;
37a0cbe5acShenning 	struct sockaddr		*sa;
387c6eb04bSreyk 	struct if_data		*ifd;
39f81902b3Sdtucker 	u_int8_t		*a6;
40f81902b3Sdtucker 	size_t			 sa6len = sizeof(struct in6_addr);
4174fd4626Shenning 	u_int			 new_cnt = 0;
427c6eb04bSreyk 	int			 tos = IPTOS_LOWDELAY, rdomain = 0;
436a5eeebaShenning 
4402d74365Sphessler 	TAILQ_FOREACH(lap, &lconf->listen_addrs, entry) {
4502d74365Sphessler 		switch (lap->sa.ss_family) {
4602d74365Sphessler 		case AF_UNSPEC:
474b8145c3Sdtucker 			if (getifaddrs(&ifa) == -1)
48507aab02Salexander 				fatal("getifaddrs");
496a5eeebaShenning 
504b8145c3Sdtucker 			for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
51a0cbe5acShenning 				sa = ifap->ifa_addr;
527c6eb04bSreyk 				if (sa == NULL || SA_LEN(sa) == 0)
53507aab02Salexander 					continue;
547c6eb04bSreyk 				if (sa->sa_family == AF_LINK) {
557c6eb04bSreyk 					ifd = ifap->ifa_data;
567c6eb04bSreyk 					rdomain = ifd->ifi_rdomain;
577c6eb04bSreyk 				}
587c6eb04bSreyk 				if (sa->sa_family != AF_INET &&
597c6eb04bSreyk 				    sa->sa_family != AF_INET6)
602d4d8d49Sdtucker 					continue;
6102d74365Sphessler 				if (lap->rtable != -1 && rdomain != lap->rtable)
6202d74365Sphessler 					continue;
6302d74365Sphessler 
64f81902b3Sdtucker 				if (sa->sa_family == AF_INET &&
65f81902b3Sdtucker 				    ((struct sockaddr_in *)sa)->sin_addr.s_addr ==
66f81902b3Sdtucker 				    INADDR_ANY)
67f81902b3Sdtucker 					continue;
68f81902b3Sdtucker 
69f81902b3Sdtucker 				if (sa->sa_family == AF_INET6) {
70f81902b3Sdtucker 					a6 = ((struct sockaddr_in6 *)sa)->
71f81902b3Sdtucker 					    sin6_addr.s6_addr;
72f81902b3Sdtucker 					if (memcmp(a6, &in6addr_any, sa6len) == 0)
73f81902b3Sdtucker 						continue;
74f81902b3Sdtucker 				}
75f81902b3Sdtucker 
76507aab02Salexander 				if ((la = calloc(1, sizeof(struct listen_addr))) ==
77507aab02Salexander 				    NULL)
786a5eeebaShenning 					fatal("setup_listeners calloc");
79507aab02Salexander 
80a0cbe5acShenning 				memcpy(&la->sa, sa, SA_LEN(sa));
8102d74365Sphessler 				la->rtable = rdomain;
8202d74365Sphessler 
8396f46bd6Sotto 				TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry);
846a5eeebaShenning 			}
856a5eeebaShenning 
864b8145c3Sdtucker 			freeifaddrs(ifa);
8702d74365Sphessler 		default:
8802d74365Sphessler 			continue;
89507aab02Salexander 		}
9002d74365Sphessler 	}
9102d74365Sphessler 
92507aab02Salexander 
932f3d2c48Sderaadt 	for (la = TAILQ_FIRST(&lconf->listen_addrs); la; ) {
946a5eeebaShenning 		switch (la->sa.ss_family) {
956a5eeebaShenning 		case AF_INET:
96a0cbe5acShenning 			if (((struct sockaddr_in *)&la->sa)->sin_port == 0)
97a0cbe5acShenning 				((struct sockaddr_in *)&la->sa)->sin_port =
986a5eeebaShenning 				    se->s_port;
996a5eeebaShenning 			break;
1006a5eeebaShenning 		case AF_INET6:
101a0cbe5acShenning 			if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0)
102a0cbe5acShenning 				((struct sockaddr_in6 *)&la->sa)->sin6_port =
1036a5eeebaShenning 				    se->s_port;
1046a5eeebaShenning 			break;
10502d74365Sphessler 		case AF_UNSPEC:
10602d74365Sphessler 			nla = TAILQ_NEXT(la, entry);
10702d74365Sphessler 			TAILQ_REMOVE(&lconf->listen_addrs, la, entry);
10802d74365Sphessler 			free(la);
10902d74365Sphessler 			la = nla;
11002d74365Sphessler 			continue;
1116a5eeebaShenning 		default:
1126a5eeebaShenning 			fatalx("king bula sez: af borked");
1136a5eeebaShenning 		}
1146a5eeebaShenning 
11502d74365Sphessler 		log_info("listening on %s %s",
11602d74365Sphessler 		    log_sockaddr((struct sockaddr *)&la->sa),
11702d74365Sphessler 		    print_rtable(la->rtable));
118507aab02Salexander 
1196a5eeebaShenning 		if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
1206a5eeebaShenning 			fatal("socket");
1216a5eeebaShenning 
12261fd8868Sdtucker 		if (la->sa.ss_family == AF_INET && setsockopt(la->fd,
12361fd8868Sdtucker 		    IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1)
12462d6660dSdtucker 			log_warn("setsockopt IPTOS_LOWDELAY");
12562d6660dSdtucker 
126f8126902Sphessler 		if (la->rtable != -1 &&
127f8126902Sphessler 		    setsockopt(la->fd, SOL_SOCKET, SO_RTABLE, &la->rtable,
12802d74365Sphessler 		    sizeof(la->rtable)) == -1)
12902d74365Sphessler 			fatal("setup_listeners setsockopt SO_RTABLE");
13002d74365Sphessler 
1316c5088d2Sdtucker 		if (bind(la->fd, (struct sockaddr *)&la->sa,
1322f3d2c48Sderaadt 		    SA_LEN((struct sockaddr *)&la->sa)) == -1) {
1332f3d2c48Sderaadt 			log_warn("bind on %s failed, skipping",
1342f3d2c48Sderaadt 			    log_sockaddr((struct sockaddr *)&la->sa));
1352f3d2c48Sderaadt 			close(la->fd);
1362f3d2c48Sderaadt 			nla = TAILQ_NEXT(la, entry);
1372f3d2c48Sderaadt 			TAILQ_REMOVE(&lconf->listen_addrs, la, entry);
1382f3d2c48Sderaadt 			free(la);
1392f3d2c48Sderaadt 			la = nla;
1402f3d2c48Sderaadt 			continue;
1412f3d2c48Sderaadt 		}
1422f3d2c48Sderaadt 		new_cnt++;
1432f3d2c48Sderaadt 		la = TAILQ_NEXT(la, entry);
1446a5eeebaShenning 	}
1456a5eeebaShenning 
14674fd4626Shenning 	*cnt = new_cnt;
14774fd4626Shenning 
1486a5eeebaShenning 	return (0);
1496a5eeebaShenning }
1506a5eeebaShenning 
1516a5eeebaShenning int
server_dispatch(int fd,struct ntpd_conf * lconf)15296f46bd6Sotto server_dispatch(int fd, struct ntpd_conf *lconf)
1536a5eeebaShenning {
1542e1afa7aSalexander 	ssize_t			 size;
1552e1afa7aSalexander 	double			 rectime;
1562e1afa7aSalexander 	struct sockaddr_storage	 fsa;
1572e1afa7aSalexander 	socklen_t		 fsa_len;
1582e1afa7aSalexander 	struct ntp_msg		 query, reply;
1592e1afa7aSalexander 	char			 buf[NTP_MSGSIZE];
1606a5eeebaShenning 
1612e1afa7aSalexander 	fsa_len = sizeof(fsa);
1622e1afa7aSalexander 	if ((size = recvfrom(fd, &buf, sizeof(buf), 0,
16301c645f0Shenning 	    (struct sockaddr *)&fsa, &fsa_len)) == -1) {
16401c645f0Shenning 		if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
165ab51698fSdtucker 		    errno == ENETUNREACH || errno == ENETDOWN) {
16601c645f0Shenning 			log_warn("recvfrom %s",
16701c645f0Shenning 			    log_sockaddr((struct sockaddr *)&fsa));
16801c645f0Shenning 			return (0);
16901c645f0Shenning 		} else
1702e1afa7aSalexander 			fatal("recvfrom");
17101c645f0Shenning 	}
1722e1afa7aSalexander 
1734e6294c2Sotto 	rectime = gettime_corrected();
1742e1afa7aSalexander 
175a6c97c40Sdtucker 	if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1)
176e9be5ca9Salexander 		return (0);
1776a5eeebaShenning 
178842d7e97Sbcook 	memset(&reply, 0, sizeof(reply));
17996f46bd6Sotto 	if (lconf->status.synced)
18096f46bd6Sotto 		reply.status = lconf->status.leap;
181a24621cfSdtucker 	else
182a24621cfSdtucker 		reply.status = LI_ALARM;
183a24621cfSdtucker 	reply.status |= (query.status & VERSIONMASK);
1842e1afa7aSalexander 	if ((query.status & MODEMASK) == MODE_CLIENT)
1856a5eeebaShenning 		reply.status |= MODE_SERVER;
186e72b8f28Shenning 	else if ((query.status & MODEMASK) == MODE_SYM_ACT)
1876a5eeebaShenning 		reply.status |= MODE_SYM_PAS;
188e72b8f28Shenning 	else /* ignore packets of different type (e.g. bcast) */
189e72b8f28Shenning 		return (0);
1906a5eeebaShenning 
19196f46bd6Sotto 	reply.stratum =	lconf->status.stratum;
1922e1afa7aSalexander 	reply.ppoll = query.ppoll;
19396f46bd6Sotto 	reply.precision = lconf->status.precision;
1942e1afa7aSalexander 	reply.rectime = d_to_lfp(rectime);
19596f46bd6Sotto 	reply.reftime = d_to_lfp(lconf->status.reftime);
1964e6294c2Sotto 	reply.xmttime = d_to_lfp(gettime_corrected());
1972e1afa7aSalexander 	reply.orgtime = query.xmttime;
19896f46bd6Sotto 	reply.rootdelay = d_to_sfp(lconf->status.rootdelay);
19996f46bd6Sotto 	reply.refid = lconf->status.refid;
2006a5eeebaShenning 
20180d85ff8Smglocker 	ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply);
2020ebe7dafShenning 	return (0);
2036a5eeebaShenning }
204