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
32 int
setup_listeners(struct servent * se,struct ntpd_conf * lconf,u_int * cnt)33 setup_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
151 int
server_dispatch(int fd,struct ntpd_conf * lconf)152 server_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