Merge from vendor branch NTPD:
[dragonfly.git] / contrib / ntpd / server.c
1 /*      $OpenBSD: server.c,v 1.20 2004/12/22 05:36:11 dtucker 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 #include "ntp.h"
30
31 int
32 setup_listeners(struct servent *se, struct ntpd_conf *conf, u_int *cnt)
33 {
34         struct listen_addr      *la;
35         struct ifaddrs          *ifa, *ifap;
36         struct sockaddr         *sa;
37         u_int                    new_cnt = 0;
38         int                      tos = IPTOS_LOWDELAY;
39
40         if (conf->listen_all) {
41                 if (getifaddrs(&ifa) == -1)
42                         fatal("getifaddrs");
43
44                 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
45                         sa = ifap->ifa_addr;
46
47                         if (sa->sa_family != AF_INET &&
48                             sa->sa_family != AF_INET6)
49                                 continue;
50
51                         if ((la = calloc(1, sizeof(struct listen_addr))) ==
52                             NULL)
53                                 fatal("setup_listeners calloc");
54
55                         memcpy(&la->sa, sa, SA_LEN(sa));
56                         TAILQ_INSERT_TAIL(&conf->listen_addrs, la, entry);
57                 }
58
59                 freeifaddrs(ifa);
60         }
61
62         TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
63                 new_cnt++;
64
65                 switch (la->sa.ss_family) {
66                 case AF_INET:
67                         if (((struct sockaddr_in *)&la->sa)->sin_port == 0)
68                                 ((struct sockaddr_in *)&la->sa)->sin_port =
69                                     se->s_port;
70                         break;
71                 case AF_INET6:
72                         if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0)
73                                 ((struct sockaddr_in6 *)&la->sa)->sin6_port =
74                                     se->s_port;
75                         break;
76                 default:
77                         fatalx("king bula sez: af borked");
78                 }
79
80                 log_info("listening on %s",
81                     log_sockaddr((struct sockaddr *)&la->sa));
82
83                 if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1)
84                         fatal("socket");
85
86                 if (la->sa.ss_family == AF_INET && setsockopt(la->fd,
87                     IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1)
88                         log_warn("setsockopt IPTOS_LOWDELAY");
89
90                 if (bind(la->fd, (struct sockaddr *)&la->sa,
91                     SA_LEN((struct sockaddr *)&la->sa)) == -1)
92                         fatal("bind");
93         }
94
95         *cnt = new_cnt;
96
97         return (0);
98 }
99
100 int
101 server_dispatch(int fd, struct ntpd_conf *conf)
102 {
103         ssize_t                  size;
104         u_int8_t                 version;
105         double                   rectime;
106         struct sockaddr_storage  fsa;
107         socklen_t                fsa_len;
108         struct ntp_msg           query, reply;
109         char                     buf[NTP_MSGSIZE];
110
111         fsa_len = sizeof(fsa);
112         if ((size = recvfrom(fd, &buf, sizeof(buf), 0,
113             (struct sockaddr *)&fsa, &fsa_len)) == -1) {
114                 if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
115                     errno == ENETUNREACH || errno == ENETDOWN) {
116                         log_warn("recvfrom %s",
117                             log_sockaddr((struct sockaddr *)&fsa));
118                         return (0);
119                 } else
120                         fatal("recvfrom");
121         }
122
123         rectime = gettime();
124
125         if (ntp_getmsg(buf, size, &query) == -1)
126                 return (0);
127
128         version = (query.status & VERSIONMASK) >> 3;
129
130         bzero(&reply, sizeof(reply));
131         reply.status = conf->status.leap | (query.status & VERSIONMASK);
132         if ((query.status & MODEMASK) == MODE_CLIENT)
133                 reply.status |= MODE_SERVER;
134         else
135                 reply.status |= MODE_SYM_PAS;
136
137         reply.stratum = conf->status.stratum;
138         reply.ppoll = query.ppoll;
139         reply.precision = conf->status.precision;
140         reply.rectime = d_to_lfp(rectime);
141         reply.reftime = d_to_lfp(conf->status.reftime);
142         reply.xmttime = d_to_lfp(gettime());
143         reply.orgtime = query.xmttime;
144         reply.rootdelay = d_to_sfp(conf->status.rootdelay);
145
146         if (version > 3)
147                 reply.refid = reply.xmttime.fractionl;
148         else
149                 reply.refid = conf->status.refid;
150
151         ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0);
152         return (0);
153 }