]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/sntp/internet.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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,
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
75     res = NULL;
76     memset(address, 0, sizeof(struct sockaddr_storage));
77     memset(anywhere, 0, sizeof(struct sockaddr_storage));
78
79     if (setjmp(jump_buffer))
80         fatal(0,"unable to set up access to NTP server %s",hostname);
81     errno = 0;
82     if (signal(SIGALRM,jump_handler) == SIG_ERR)
83         fatal(1,"unable to set up signal handler",NULL);
84     alarm((unsigned int)timespan);
85
86 /* Look up the Internet name or IP number. */
87     memset(&hints, 0, sizeof(hints));
88     hints.ai_socktype = SOCK_DGRAM;
89     hints.ai_family = pref_family;
90     rval = getaddrinfo(hostname, "ntp", &hints, &res);
91     if (rval != 0)
92         fatal(0, "getaddrinfo(hostname, ntp)  failed with %s",
93             gai_strerror(rval));
94
95 /* Now clear the timer and check the result. */
96
97     clear_alarm();
98     /* There can be more than one address in the list, but for now only
99     use the first. */
100     memcpy(address, res->ai_addr, res->ai_addrlen);
101     family = res->ai_family;
102     freeaddrinfo(res);
103
104     switch(family) {
105     case AF_INET:
106         hints.ai_family = AF_INET;
107         hints.ai_flags = AI_PASSIVE;
108         rval = getaddrinfo(NULL, "ntp", &hints, &res);
109         if (rval != 0)
110             fatal(0, "getaddrinfo(NULL, ntp) failed with %s",
111                 gai_strerror(rval));
112         memcpy(anywhere, res->ai_addr, res->ai_addrlen);
113         freeaddrinfo(res);
114         break;
115     case AF_INET6:
116         hints.ai_family = AF_INET6;
117         hints.ai_flags = AI_PASSIVE;
118         rval = getaddrinfo(NULL, "ntp", &hints, &res);
119         if (rval != 0)
120             fatal(0, "getaddrinfo(NULL, ntp, INET6, AI_PASSIVE) failed with %s",
121                 gai_strerror(rval));
122         memcpy(anywhere, res->ai_addr, res->ai_addrlen);
123         freeaddrinfo(res);
124         break;
125     }
126 }
127
128 #else
129
130 void find_address (struct in_addr *address, struct in_addr *anywhere,
131     int *port, char *hostname, int timespan) {
132
133 /* Locate the specified NTP server and return its Internet address and port 
134 number. */
135
136     unsigned long ipaddr;
137     struct in_addr nowhere[1];
138     struct hostent *host;
139     struct servent *service;
140
141 /* Set up the reserved Internet addresses, attempting not to assume that
142 addresses are 32 bits. */
143
144     local_to_address(nowhere,INADDR_LOOPBACK);
145     local_to_address(anywhere,INADDR_ANY);
146
147 /* Check the address, if any.  This assumes that the DNS is reliable, or is at
148 least checked by someone else.  But it doesn't assume that it is accessible, so
149 it needs to set up a timeout. */
150
151     if (hostname == NULL)
152         *address = *anywhere;
153     else {
154         if (setjmp(jump_buffer))
155             fatal(0,"unable to set up access to NTP server %s",hostname);
156         errno = 0;
157         if (signal(SIGALRM,jump_handler) == SIG_ERR)
158             fatal(1,"unable to set up signal handler",NULL);
159         alarm((unsigned int)timespan);
160
161 /* Look up the Internet name or IP number. */
162
163         if (! isdigit(hostname[0])) {
164             errno = 0;
165             host = gethostbyname(hostname);
166         } else {
167             if ((ipaddr = inet_addr(hostname)) == (unsigned long)-1)
168                 fatal(0,"invalid IP number %s",hostname);
169             network_to_address(address,ipaddr);
170             errno = 0;
171             host = gethostbyaddr((void *)address,sizeof(struct in_addr),
172                 AF_INET);
173         }
174
175 /* Now clear the timer and check the result. */
176
177         clear_alarm();
178         if (host == NULL) fatal(1,"unable to locate IP address/number",NULL);
179         if (host->h_length != sizeof(struct in_addr))
180             fatal(0,"the address does not seem to be an Internet one",NULL);
181         *address = *((struct in_addr **)host->h_addr_list)[0];
182         if (memcmp(address,nowhere,sizeof(struct in_addr)) == 0
183             || memcmp(address,anywhere,sizeof(struct in_addr)) == 0)
184             fatal(0,"reserved IP numbers cannot be used",NULL);
185         if (verbose)
186             fprintf(stderr,
187                 "%s: using NTP server %s (%s)\n",
188                 argv0,host->h_name,inet_ntoa(*address));
189     }
190
191 /* Find out the port number (usually from /etc/services), and leave it in 
192 network format.  This is assumed not to be obtained from a network service!
193 Note that a port number is not assumed to be 16 bits. */
194
195     if ((service = getservbyname("ntp","udp")) != NULL) {
196         *port = service->s_port;
197         if (verbose > 2)
198             fprintf(stderr,"Using port %d for NTP\n",port_to_integer(*port));
199     } else {
200         *port = NTP_PORT;
201         if (verbose)
202             fprintf(stderr,
203                 "%s: assuming port %d for NTP - check /etc/services\n",
204                 argv0,port_to_integer(*port));
205     }
206 }
207 #endif