xref: /openbsd-src/usr.sbin/ntpd/server.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: server.c,v 1.36 2011/09/21 15:41:30 phessler 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 MIND, USE, DATA OR PROFITS, WHETHER
16  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/ioctl.h>
21 #include <sys/types.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 ifreq		 ifr;
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, fd;
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 ||
53 				    (sa->sa_family != AF_INET &&
54 				    sa->sa_family != AF_INET6))
55 					continue;
56 				if (SA_LEN(sa) == 0)
57 					continue;
58 
59 				strlcpy(ifr.ifr_name, ifap->ifa_name,
60 				    sizeof(ifr.ifr_name));
61 
62 				fd = socket(AF_INET, SOCK_DGRAM, 0);
63 				if (ioctl(fd, SIOCGIFRDOMAIN,
64 				    (caddr_t)&ifr) == -1)
65 			                rdomain = 0;
66 			        else
67 			                rdomain = ifr.ifr_rdomainid;
68 				close(fd);
69 
70 				if (lap->rtable != -1 && rdomain != lap->rtable)
71 					continue;
72 
73 				if (sa->sa_family == AF_INET &&
74 				    ((struct sockaddr_in *)sa)->sin_addr.s_addr ==
75 				    INADDR_ANY)
76 					continue;
77 
78 				if (sa->sa_family == AF_INET6) {
79 					a6 = ((struct sockaddr_in6 *)sa)->
80 					    sin6_addr.s6_addr;
81 					if (memcmp(a6, &in6addr_any, sa6len) == 0)
82 						continue;
83 				}
84 
85 				if ((la = calloc(1, sizeof(struct listen_addr))) ==
86 				    NULL)
87 					fatal("setup_listeners calloc");
88 
89 				memcpy(&la->sa, sa, SA_LEN(sa));
90 				la->rtable = rdomain;
91 
92 				TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry);
93 			}
94 
95 			freeifaddrs(ifa);
96 		default:
97 			continue;
98 		}
99 	}
100 
101 
102 	for (la = TAILQ_FIRST(&lconf->listen_addrs); la; ) {
103 		switch (la->sa.ss_family) {
104 		case AF_INET:
105 			if (((struct sockaddr_in *)&la->sa)->sin_port == 0)
106 				((struct sockaddr_in *)&la->sa)->sin_port =
107 				    se->s_port;
108 			break;
109 		case AF_INET6:
110 			if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0)
111 				((struct sockaddr_in6 *)&la->sa)->sin6_port =
112 				    se->s_port;
113 			break;
114 		case AF_UNSPEC:
115 			nla = TAILQ_NEXT(la, entry);
116 			TAILQ_REMOVE(&lconf->listen_addrs, la, entry);
117 			free(la);
118 			la = nla;
119 			continue;
120 		default:
121 			fatalx("king bula sez: af borked");
122 		}
123 
124 		log_info("listening on %s %s",
125 		    log_sockaddr((struct sockaddr *)&la->sa),
126 		    print_rtable(la->rtable));
127 
128 		if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
129 			fatal("socket");
130 
131 		if (la->sa.ss_family == AF_INET && setsockopt(la->fd,
132 		    IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1)
133 			log_warn("setsockopt IPTOS_LOWDELAY");
134 
135 		if (la->sa.ss_family == AF_INET && la->rtable != -1 &&
136 		    setsockopt(la->fd, IPPROTO_IP, SO_RTABLE, &la->rtable,
137 		    sizeof(la->rtable)) == -1)
138 			fatal("setup_listeners setsockopt SO_RTABLE");
139 
140 		if (bind(la->fd, (struct sockaddr *)&la->sa,
141 		    SA_LEN((struct sockaddr *)&la->sa)) == -1) {
142 			log_warn("bind on %s failed, skipping",
143 			    log_sockaddr((struct sockaddr *)&la->sa));
144 			close(la->fd);
145 			nla = TAILQ_NEXT(la, entry);
146 			TAILQ_REMOVE(&lconf->listen_addrs, la, entry);
147 			free(la);
148 			la = nla;
149 			continue;
150 		}
151 		new_cnt++;
152 		la = TAILQ_NEXT(la, entry);
153 	}
154 
155 	*cnt = new_cnt;
156 
157 	return (0);
158 }
159 
160 int
161 server_dispatch(int fd, struct ntpd_conf *lconf)
162 {
163 	ssize_t			 size;
164 	u_int8_t		 version;
165 	double			 rectime;
166 	struct sockaddr_storage	 fsa;
167 	socklen_t		 fsa_len;
168 	struct ntp_msg		 query, reply;
169 	char			 buf[NTP_MSGSIZE];
170 
171 	fsa_len = sizeof(fsa);
172 	if ((size = recvfrom(fd, &buf, sizeof(buf), 0,
173 	    (struct sockaddr *)&fsa, &fsa_len)) == -1) {
174 		if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
175 		    errno == ENETUNREACH || errno == ENETDOWN) {
176 			log_warn("recvfrom %s",
177 			    log_sockaddr((struct sockaddr *)&fsa));
178 			return (0);
179 		} else
180 			fatal("recvfrom");
181 	}
182 
183 	rectime = gettime_corrected();
184 
185 	if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1)
186 		return (0);
187 
188 	version = (query.status & VERSIONMASK) >> 3;
189 
190 	bzero(&reply, sizeof(reply));
191 	if (lconf->status.synced)
192 		reply.status = lconf->status.leap;
193 	else
194 		reply.status = LI_ALARM;
195 	reply.status |= (query.status & VERSIONMASK);
196 	if ((query.status & MODEMASK) == MODE_CLIENT)
197 		reply.status |= MODE_SERVER;
198 	else if ((query.status & MODEMASK) == MODE_SYM_ACT)
199 		reply.status |= MODE_SYM_PAS;
200 	else /* ignore packets of different type (e.g. bcast) */
201 		return (0);
202 
203 	reply.stratum =	lconf->status.stratum;
204 	reply.ppoll = query.ppoll;
205 	reply.precision = lconf->status.precision;
206 	reply.rectime = d_to_lfp(rectime);
207 	reply.reftime = d_to_lfp(lconf->status.reftime);
208 	reply.xmttime = d_to_lfp(gettime_corrected());
209 	reply.orgtime = query.xmttime;
210 	reply.rootdelay = d_to_sfp(lconf->status.rootdelay);
211 	reply.refid = lconf->status.refid;
212 
213 	ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0);
214 	return (0);
215 }
216