]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/sntp/internet.c
Fix compilation with gcc 4.1. This is imported on the vendor branch as it
[FreeBSD/FreeBSD.git] / contrib / ntp / sntp / internet.c
1 /*  Copyright (C) 1996 N.M. Maclaren
2     Copyright (C) 1996 The University of Cambridge
3
4 This includes all of the code needed to handle Internet addressing.  It is way
5 outside current POSIX, unfortunately.  It should be easy to convert to a system
6 that uses another mechanism.  The signal handling is not necessary for its
7 function, but is an attempt to avoid the program hanging when the name server
8 is inaccessible. */
9
10
11
12 #include "header.h"
13 #include "internet.h"
14
15 #include <netdb.h>
16 #include <arpa/inet.h>
17
18 #define INTERNET
19 #include "kludges.h"
20 #undef INTERNET
21
22
23 /* Used to force dns resolving to ipv4 or ipv6 addresses. */
24 static int pref_family;
25
26 /* There needs to be some disgusting grobble for handling timeouts, which is
27 identical to the grobble in socket.c. */
28
29 static jmp_buf jump_buffer;
30
31 static void jump_handler (int sig) {
32     longjmp(jump_buffer,1);
33 }
34
35 static void clear_alarm (void) {
36     int k;
37
38     k = errno;
39     alarm(0);
40     errno = 0;
41     if (signal(SIGALRM,SIG_DFL) == SIG_ERR)
42         fatal(1,"unable to reset signal handler",NULL);
43     errno = k;
44 }
45
46 void preferred_family(int fam) {
47         switch(fam) {
48         case PREF_FAM_INET:
49             pref_family = AF_INET;
50             break;
51 #ifdef HAVE_IPV6
52         case PREF_FAM_INET6:
53             pref_family = AF_INET6;
54             break;
55 #endif
56         default:
57             fatal(0,"unable to set the preferred family", NULL);
58             break;
59         }
60 }
61
62 #ifdef HAVE_IPV6
63
64 void find_address (struct sockaddr_storage *address,
65     struct sockaddr_storage *anywhere, struct sockaddr_storage *everywhere,
66     int *port, char *hostname, int timespan) {
67
68 /* Locate the specified NTP server and return its Internet address and port 
69 number. */
70
71     int family, rval;
72     struct addrinfo hints;
73     struct addrinfo *res;
74     struct sockaddr_in *sin;
75     struct sockaddr_in6 *sin6;
76
77     res = NULL;
78     memset(address, 0, sizeof(struct sockaddr_storage));
79     memset(anywhere, 0, sizeof(struct sockaddr_storage));
80     memset(everywhere, 0, sizeof(struct sockaddr_storage));
81
82     if (setjmp(jump_buffer))
83         fatal(0,"unable to set up access to NTP server %s",hostname);
84     errno = 0;
85     if (signal(SIGALRM,jump_handler) == SIG_ERR)
86         fatal(1,"unable to set up signal handler",NULL);
87     alarm((unsigned int)timespan);
88
89 /* Look up the Internet name or IP number. */
90     memset(&hints, 0, sizeof(hints));
91     hints.ai_socktype = SOCK_DGRAM;
92     hints.ai_family = pref_family;
93     rval = getaddrinfo(hostname, "ntp", &hints, &res);
94     if (rval != 0)
95         fatal(0, "getaddrinfo failed with %s", gai_strerror(rval));
96
97 /* Now clear the timer and check the result. */
98
99     clear_alarm();
100     /* There can be more than one address in the list, but for now only
101     use the first. */
102     memcpy(address, res->ai_addr, res->ai_addrlen);
103     family = res->ai_family;
104     freeaddrinfo(res);
105
106     switch(family) {
107     case AF_INET:
108         hints.ai_family = AF_INET;
109         hints.ai_flags = AI_PASSIVE;
110         rval = getaddrinfo(NULL, "ntp", &hints, &res);
111         if (rval != 0)
112             fatal(0, "getaddrinfo failed with %s", gai_strerror(rval));
113         memcpy(anywhere, res->ai_addr, res->ai_addrlen);
114         freeaddrinfo(res);
115         rval = getaddrinfo("255.255.255.255", "ntp", &hints, &res);
116         if (rval != 0)
117             fatal(0, "getaddrinfo failed with %s", gai_strerror(rval));
118         memcpy(everywhere, res->ai_addr, res->ai_addrlen);
119         freeaddrinfo(res);
120         break;
121     case AF_INET6:
122         hints.ai_family = AF_INET6;
123         hints.ai_flags = AI_PASSIVE;
124         rval = getaddrinfo(NULL, "ntp", &hints, &res);
125         if (rval != 0)
126             fatal(0, "getaddrinfo failed with %s", gai_strerror(rval));
127         memcpy(anywhere, res->ai_addr, res->ai_addrlen);
128         freeaddrinfo(res);
129         /* IPv6 do not have broadcast, give it loopback. */
130         hints.ai_flags = 0;
131         rval = getaddrinfo(NULL, "ntp", &hints, &res);
132         if (rval != 0)
133             fatal(0, "getaddrinfo failed with %s", gai_strerror(rval));
134         memcpy(everywhere, res->ai_addr, res->ai_addrlen);
135         freeaddrinfo(res);
136         break;
137     }
138 }
139
140 #else
141
142 void find_address (struct in_addr *address, struct in_addr *anywhere,
143     struct in_addr *everywhere, int *port, char *hostname, int timespan) {
144
145 /* Locate the specified NTP server and return its Internet address and port 
146 number. */
147
148     unsigned long ipaddr;
149     struct in_addr nowhere[1];
150     struct hostent *host;
151     struct servent *service;
152
153 /* Set up the reserved Internet addresses, attempting not to assume that
154 addresses are 32 bits. */
155
156     local_to_address(nowhere,INADDR_LOOPBACK);
157     local_to_address(anywhere,INADDR_ANY);
158     local_to_address(everywhere,INADDR_BROADCAST);
159
160 /* Check the address, if any.  This assumes that the DNS is reliable, or is at
161 least checked by someone else.  But it doesn't assume that it is accessible, so
162 it needs to set up a timeout. */
163
164     if (hostname == NULL)
165         *address = *anywhere;
166     else {
167         if (setjmp(jump_buffer))
168             fatal(0,"unable to set up access to NTP server %s",hostname);
169         errno = 0;
170         if (signal(SIGALRM,jump_handler) == SIG_ERR)
171             fatal(1,"unable to set up signal handler",NULL);
172         alarm((unsigned int)timespan);
173
174 /* Look up the Internet name or IP number. */
175
176         if (! isdigit(hostname[0])) {
177             errno = 0;
178             host = gethostbyname(hostname);
179         } else {
180             if ((ipaddr = inet_addr(hostname)) == (unsigned long)-1)
181                 fatal(0,"invalid IP number %s",hostname);
182             network_to_address(address,ipaddr);
183             errno = 0;
184             host = gethostbyaddr((void *)address,sizeof(struct in_addr),
185                 AF_INET);
186         }
187
188 /* Now clear the timer and check the result. */
189
190         clear_alarm();
191         if (host == NULL) fatal(1,"unable to locate IP address/number",NULL);
192         if (host->h_length != sizeof(struct in_addr))
193             fatal(0,"the address does not seem to be an Internet one",NULL);
194         *address = *((struct in_addr **)host->h_addr_list)[0];
195         if (memcmp(address,nowhere,sizeof(struct in_addr)) == 0 ||
196                 memcmp(address,anywhere,sizeof(struct in_addr)) == 0 ||
197                 memcmp(address,everywhere,sizeof(struct in_addr)) == 0)
198             fatal(0,"reserved IP numbers cannot be used",NULL);
199         if (verbose)
200             fprintf(stderr,
201                 "%s: using NTP server %s (%s)\n",
202                 argv0,host->h_name,inet_ntoa(*address));
203     }
204
205 /* Find out the port number (usually from /etc/services), and leave it in 
206 network format.  This is assumed not to be obtained from a network service!
207 Note that a port number is not assumed to be 16 bits. */
208
209     if ((service = getservbyname("ntp","udp")) != NULL) {
210         *port = service->s_port;
211         if (verbose > 2)
212             fprintf(stderr,"Using port %d for NTP\n",port_to_integer(*port));
213     } else {
214         *port = NTP_PORT;
215         if (verbose)
216             fprintf(stderr,
217                 "%s: assuming port %d for NTP - check /etc/services\n",
218                 argv0,port_to_integer(*port));
219     }
220 }
221 #endif