xref: /openbsd-src/usr.sbin/ntpd/server.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: server.c,v 1.34 2008/11/10 17:55:36 deraadt 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/types.h>
21 #include <sys/socket.h>
22 #include <errno.h>
23 #include <ifaddrs.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "ntpd.h"
29 
30 int
31 setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt)
32 {
33 	struct listen_addr	*la;
34 	struct ifaddrs		*ifa, *ifap;
35 	struct sockaddr		*sa;
36 	u_int8_t		*a6;
37 	size_t			 sa6len = sizeof(struct in6_addr);
38 	u_int			 new_cnt = 0;
39 	int			 tos = IPTOS_LOWDELAY;
40 
41 	if (lconf->listen_all) {
42 		if (getifaddrs(&ifa) == -1)
43 			fatal("getifaddrs");
44 
45 		for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
46 			sa = ifap->ifa_addr;
47 
48 			if (sa == NULL ||
49 			    (sa->sa_family != AF_INET &&
50 			    sa->sa_family != AF_INET6))
51 				continue;
52 			if (SA_LEN(sa) == 0)
53 				continue;
54 
55 			if (sa->sa_family == AF_INET &&
56 			    ((struct sockaddr_in *)sa)->sin_addr.s_addr ==
57 			    INADDR_ANY)
58 				continue;
59 
60 			if (sa->sa_family == AF_INET6) {
61 				a6 = ((struct sockaddr_in6 *)sa)->
62 				    sin6_addr.s6_addr;
63 				if (memcmp(a6, &in6addr_any, sa6len) == 0)
64 					continue;
65 			}
66 
67 			if ((la = calloc(1, sizeof(struct listen_addr))) ==
68 			    NULL)
69 				fatal("setup_listeners calloc");
70 
71 			memcpy(&la->sa, sa, SA_LEN(sa));
72 			TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry);
73 		}
74 
75 		freeifaddrs(ifa);
76 	}
77 
78 	for (la = TAILQ_FIRST(&lconf->listen_addrs); la; ) {
79 		switch (la->sa.ss_family) {
80 		case AF_INET:
81 			if (((struct sockaddr_in *)&la->sa)->sin_port == 0)
82 				((struct sockaddr_in *)&la->sa)->sin_port =
83 				    se->s_port;
84 			break;
85 		case AF_INET6:
86 			if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0)
87 				((struct sockaddr_in6 *)&la->sa)->sin6_port =
88 				    se->s_port;
89 			break;
90 		default:
91 			fatalx("king bula sez: af borked");
92 		}
93 
94 		log_info("listening on %s",
95 		    log_sockaddr((struct sockaddr *)&la->sa));
96 
97 		if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
98 			fatal("socket");
99 
100 		if (la->sa.ss_family == AF_INET && setsockopt(la->fd,
101 		    IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1)
102 			log_warn("setsockopt IPTOS_LOWDELAY");
103 
104 		if (bind(la->fd, (struct sockaddr *)&la->sa,
105 		    SA_LEN((struct sockaddr *)&la->sa)) == -1) {
106 			struct listen_addr	*nla;
107 
108 			log_warn("bind on %s failed, skipping",
109 			    log_sockaddr((struct sockaddr *)&la->sa));
110 			close(la->fd);
111 			nla = TAILQ_NEXT(la, entry);
112 			TAILQ_REMOVE(&lconf->listen_addrs, la, entry);
113 			free(la);
114 			la = nla;
115 			continue;
116 		}
117 		new_cnt++;
118 		la = TAILQ_NEXT(la, entry);
119 	}
120 
121 	*cnt = new_cnt;
122 
123 	return (0);
124 }
125 
126 int
127 server_dispatch(int fd, struct ntpd_conf *lconf)
128 {
129 	ssize_t			 size;
130 	u_int8_t		 version;
131 	double			 rectime;
132 	struct sockaddr_storage	 fsa;
133 	socklen_t		 fsa_len;
134 	struct ntp_msg		 query, reply;
135 	char			 buf[NTP_MSGSIZE];
136 
137 	fsa_len = sizeof(fsa);
138 	if ((size = recvfrom(fd, &buf, sizeof(buf), 0,
139 	    (struct sockaddr *)&fsa, &fsa_len)) == -1) {
140 		if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
141 		    errno == ENETUNREACH || errno == ENETDOWN) {
142 			log_warn("recvfrom %s",
143 			    log_sockaddr((struct sockaddr *)&fsa));
144 			return (0);
145 		} else
146 			fatal("recvfrom");
147 	}
148 
149 	rectime = gettime_corrected();
150 
151 	if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1)
152 		return (0);
153 
154 	version = (query.status & VERSIONMASK) >> 3;
155 
156 	bzero(&reply, sizeof(reply));
157 	if (lconf->status.synced)
158 		reply.status = lconf->status.leap;
159 	else
160 		reply.status = LI_ALARM;
161 	reply.status |= (query.status & VERSIONMASK);
162 	if ((query.status & MODEMASK) == MODE_CLIENT)
163 		reply.status |= MODE_SERVER;
164 	else
165 		reply.status |= MODE_SYM_PAS;
166 
167 	reply.stratum =	lconf->status.stratum;
168 	reply.ppoll = query.ppoll;
169 	reply.precision = lconf->status.precision;
170 	reply.rectime = d_to_lfp(rectime);
171 	reply.reftime = d_to_lfp(lconf->status.reftime);
172 	reply.xmttime = d_to_lfp(gettime_corrected());
173 	reply.orgtime = query.xmttime;
174 	reply.rootdelay = d_to_sfp(lconf->status.rootdelay);
175 	reply.refid = lconf->status.refid;
176 
177 	ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0);
178 	return (0);
179 }
180