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 |
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 |
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 |
|
|
} |