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