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