1 /** $MirOS: src/usr.sbin/ntpd/server.c,v 1.9 2010/09/21 21:24:46 tg Exp $ */
2 /* $OpenBSD: server.c,v 1.26 2005/09/24 00:32:03 dtucker Exp $ */
3
4 /*
5 * Copyright (c) 2007 Thorsten Glaser <tg@mirbsd.de>
6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7 * Copyright (c) 2004 Alexander Guy <alexander@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
18 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
19 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include <sys/types.h>
23 #include <sys/socket.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 #include "ntp.h"
32
33 __RCSID("$MirOS: src/usr.sbin/ntpd/server.c,v 1.9 2010/09/21 21:24:46 tg Exp $");
34
35 int
setup_listeners(struct servent * se,struct ntpd_conf * conf,u_int * cnt)36 setup_listeners(struct servent *se, struct ntpd_conf *conf, u_int *cnt)
37 {
38 struct listen_addr *la;
39 struct ifaddrs *ifa, *ifap;
40 struct sockaddr *sa;
41 u_int new_cnt = 0;
42 int tos = IPTOS_LOWDELAY;
43
44 if (conf->listen_all) {
45 if (getifaddrs(&ifa) == -1)
46 fatal("getifaddrs");
47
48 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
49 sa = ifap->ifa_addr;
50
51 if (SA_LEN(sa) == 0)
52 continue;
53 if (sa == NULL ||
54 (sa->sa_family != AF_INET &&
55 sa->sa_family != AF_INET6))
56 continue;
57
58 if ((la = calloc(1, sizeof(struct listen_addr))) ==
59 NULL)
60 fatal("setup_listeners calloc");
61
62 memcpy(&la->sa, sa, SA_LEN(sa));
63 TAILQ_INSERT_TAIL(&conf->listen_addrs, la, entry);
64 }
65
66 freeifaddrs(ifa);
67 }
68
69 TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
70 new_cnt++;
71
72 switch (la->sa.ss_family) {
73 case AF_INET:
74 if (((struct sockaddr_in *)&la->sa)->sin_port == 0)
75 ((struct sockaddr_in *)&la->sa)->sin_port =
76 se->s_port;
77 break;
78 case AF_INET6:
79 if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0)
80 ((struct sockaddr_in6 *)&la->sa)->sin6_port =
81 se->s_port;
82 break;
83 default:
84 fatalx("king bula sez: af borked");
85 }
86
87 log_info("listening on %s",
88 log_sockaddr((struct sockaddr *)&la->sa));
89
90 if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
91 fatal("socket");
92
93 if (la->sa.ss_family == AF_INET && setsockopt(la->fd,
94 IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1)
95 log_warn("setsockopt IPTOS_LOWDELAY");
96
97 if (bind(la->fd, (struct sockaddr *)&la->sa,
98 SA_LEN((struct sockaddr *)&la->sa)) == -1)
99 fatal("bind");
100 }
101
102 *cnt = new_cnt;
103
104 return (0);
105 }
106
107 int
server_dispatch(int fd,struct ntpd_conf * conf)108 server_dispatch(int fd, struct ntpd_conf *conf)
109 {
110 struct {
111 struct sockaddr_storage fsa_;
112 socklen_t fsa_len_;
113 struct ntp_msg query_, reply_;
114 } st;
115 #define fsa (st.fsa_)
116 #define fsa_len (st.fsa_len_)
117 #define query (st.query_)
118 #define reply (st.reply_)
119 ssize_t size;
120 double rectime;
121 char buf[NTP_MSGSIZE];
122
123 fsa_len = sizeof(fsa);
124 if ((size = recvfrom(fd, &buf, sizeof(buf), 0,
125 (struct sockaddr *)&fsa, &fsa_len)) == -1) {
126 if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
127 errno == ENETUNREACH || errno == ENETDOWN) {
128 log_warn("recvfrom %s",
129 log_sockaddr((struct sockaddr *)&fsa));
130 return (0);
131 } else
132 fatal("recvfrom");
133 }
134
135 rectime = gettime();
136
137 if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1)
138 return (0);
139
140 bzero(&reply, sizeof(reply));
141 if (conf->status.synced)
142 reply.status = conf->status.leap;
143 else
144 reply.status = LI_ALARM;
145 reply.status |= (query.status & VERSIONMASK);
146 if ((query.status & MODEMASK) == MODE_CLIENT)
147 reply.status |= MODE_SERVER;
148 else if ((query.status & MODEMASK) == MODE_SYM_ACT)
149 reply.status |= MODE_SYM_PAS;
150 else
151 /* reserved, broadcast, control msg, private use */
152 goto out;
153
154 reply.stratum = conf->status.stratum;
155 reply.ppoll = query.ppoll;
156 reply.precision = conf->status.precision;
157 reply.rectime = d_to_lfp(rectime);
158 reply.reftime = d_to_lfp(conf->status.reftime);
159 reply.orgtime = query.xmttime;
160 reply.rootdelay = d_to_sfp(conf->status.rootdelay);
161
162 if (((query.status & VERSIONMASK) >> 3) > 3 && reply.stratum > 1)
163 reply.refid = conf->status.refid4;
164 else
165 reply.refid = conf->status.refid;
166
167 reply.xmttime = d_to_lfp(gettime());
168 ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0);
169 out:
170 arc4random_pushb_fast(&st, sizeof(st));
171 return (0);
172 }
173