1132451Sroberto/*  Copyright (C) 1996, 2000 N.M. Maclaren
2132451Sroberto    Copyright (C) 1996, 2000 The University of Cambridge
3132451Sroberto
4132451SrobertoThis includes all of the code needed to handle Berkeley sockets.  It is way
5132451Srobertooutside current POSIX, unfortunately.  It should be easy to convert to a system
6132451Srobertothat uses another mechanism.  It does not currently use socklen_t, because
7132451Srobertothe only system that the author uses that has it is Linux. */
8132451Sroberto
9132451Sroberto
10132451Sroberto
11182007Sroberto#include "config.h"
12182007Sroberto
13132451Sroberto#include "header.h"
14132451Sroberto#include "internet.h"
15132451Sroberto#include <fcntl.h>
16132451Sroberto
17132451Sroberto#define SOCKET
18132451Sroberto#include "kludges.h"
19132451Sroberto#undef SOCKET
20132451Sroberto
21132451Sroberto
22132451Sroberto
23132451Sroberto/* The code needs to set some variables during the open, for use by later
24132451Srobertofunctions. */
25132451Sroberto
26132451Srobertostatic int initial = 1,
27132451Sroberto    descriptors[MAX_SOCKETS];
28132451Sroberto
29132451Sroberto#ifdef HAVE_IPV6
30132451Srobertostatic struct sockaddr_storage here[MAX_SOCKETS], there[MAX_SOCKETS];
31132451Sroberto#else
32132451Srobertostatic struct sockaddr_in here[MAX_SOCKETS], there[MAX_SOCKETS];
33132451Sroberto#endif
34132451Sroberto
35182007Srobertovoid display_in_hex(const void *, int);
36182007Sroberto#ifdef HAVE_IPV6
37182007Srobertovoid display_sock_in_hex(struct sockaddr_storage *);
38182007Sroberto#else
39182007Srobertovoid display_sock_in_hex (struct sockaddr_in *);
40182007Sroberto#endif
41132451Sroberto
42132451Sroberto/* There needs to be some disgusting grobble for handling timeouts, that is
43132451Srobertoidentical to the grobble in internet.c. */
44132451Sroberto
45132451Srobertostatic jmp_buf jump_buffer;
46132451Sroberto
47132451Srobertostatic void jump_handler (int sig) {
48132451Sroberto    longjmp(jump_buffer,1);
49132451Sroberto}
50132451Sroberto
51132451Srobertostatic void clear_alarm (void) {
52132451Sroberto    int k;
53132451Sroberto
54132451Sroberto    k = errno;
55132451Sroberto    alarm(0);
56132451Sroberto    errno = 0;
57132451Sroberto    if (signal(SIGALRM,SIG_DFL) == SIG_ERR)
58132451Sroberto        fatal(1,"unable to reset signal handler",NULL);
59132451Sroberto    errno = k;
60132451Sroberto}
61132451Sroberto
62132451Sroberto
63132451Sroberto
64132451Srobertovoid display_in_hex (const void *data, int length) {
65132451Sroberto    int i;
66132451Sroberto
67132451Sroberto    for (i = 0; i < length; ++i)
68132451Sroberto        fprintf(stderr,"%.2x",((const unsigned char *)data)[i]);
69132451Sroberto}
70132451Sroberto
71132451Sroberto#ifdef HAVE_IPV6
72132451Sroberto
73132451Srobertovoid display_sock_in_hex (struct sockaddr_storage *sock) {
74182007Sroberto    int family;
75132451Sroberto    struct sockaddr_in *sin;
76132451Sroberto    struct sockaddr_in6 *sin6;
77132451Sroberto
78132451Sroberto    family = sock->ss_family;
79132451Sroberto    switch(family) {
80132451Sroberto    case AF_INET:
81132451Sroberto	sin = (struct sockaddr_in *)sock;
82132451Sroberto	display_in_hex(&sin->sin_addr, sizeof(struct in_addr));
83132451Sroberto	fprintf(stderr,"/");
84132451Sroberto	display_in_hex(&sin->sin_port, 2);
85132451Sroberto	break;
86132451Sroberto    case AF_INET6:
87132451Sroberto	sin6 = (struct sockaddr_in6 *)sock;
88132451Sroberto	display_in_hex(&sin6->sin6_addr, sizeof(struct in6_addr));
89132451Sroberto	fprintf(stderr,"/");
90132451Sroberto	display_in_hex(&sin6->sin6_port, 2);
91132451Sroberto	break;
92132451Sroberto    }
93132451Sroberto}
94132451Sroberto
95132451Sroberto#else
96132451Sroberto
97132451Srobertovoid display_sock_in_hex (struct sockaddr_in *sock) {
98132451Sroberto    int family, len;
99132451Sroberto    struct sockaddr_in *sin;
100132451Sroberto
101132451Sroberto    family = sock->sin_family;
102132451Sroberto    switch(family) {
103132451Sroberto    case AF_INET:
104132451Sroberto	sin = (struct sockaddr_in *)sock;
105132451Sroberto	display_in_hex(&sin->sin_addr, sizeof(struct in_addr));
106132451Sroberto	fprintf(stderr,"/");
107132451Sroberto	display_in_hex(&sin->sin_port, 2);
108132451Sroberto	break;
109132451Sroberto    }
110132451Sroberto}
111132451Sroberto#endif
112132451Sroberto
113182007Srobertoextern int unprivport;
114182007Sroberto
115132451Sroberto#ifdef HAVE_IPV6
116132451Sroberto
117132451Srobertovoid open_socket (int which, char *hostname, int timespan) {
118132451Sroberto
119132451Sroberto/* Locate the specified NTP server, set up a couple of addresses and open a
120132451Srobertosocket. */
121132451Sroberto
122132451Sroberto    int port, k, sl;
123182007Sroberto    struct sockaddr_storage address, anywhere;
124132451Sroberto
125132451Sroberto/* Initialise and find out the server and port number.  Note that the port
126132451Srobertonumber is in network format. */
127132451Sroberto
128132451Sroberto    if (initial)
129132451Sroberto	for (k = 0; k < MAX_SOCKETS; ++k)
130132451Sroberto	    descriptors[k] = -1;
131132451Sroberto    initial = 0;
132132451Sroberto    if (which < 0 || which >= MAX_SOCKETS || descriptors[which] >= 0)
133132451Sroberto        fatal(0,"socket index out of range or already open",NULL);
134132451Sroberto    if (verbose > 2)
135132451Sroberto	fprintf(stderr,"Looking for the socket addresses\n");
136182007Sroberto    find_address(&address,&anywhere,&port,hostname,timespan);
137132451Sroberto    if (verbose > 2) {
138132451Sroberto        fprintf(stderr,"Internet address: address=");
139132451Sroberto        display_sock_in_hex(&address);
140132451Sroberto        fprintf(stderr," anywhere=");
141132451Sroberto        display_sock_in_hex(&anywhere);
142132451Sroberto        fputc('\n',stderr);
143132451Sroberto    }
144132451Sroberto
145132451Sroberto/* Set up our own and the target addresses.  Note that the target address will
146132451Srobertobe reset before use in server mode. */
147132451Sroberto
148132451Sroberto    memset(&here[which], 0, sizeof(struct sockaddr_storage));
149132451Sroberto    here[which] = anywhere;
150182007Sroberto    if (operation != op_listen || unprivport)
151132451Sroberto        ((struct sockaddr_in6 *)&here[which])->sin6_port = 0;
152132451Sroberto    memset(&there[which], 0, sizeof(struct sockaddr_storage));
153182007Sroberto    there[which] = address;
154132451Sroberto    if (verbose > 2) {
155132451Sroberto        fprintf(stderr,"Initial sockets: here=");
156132451Sroberto        display_sock_in_hex(&here[which]);
157132451Sroberto        fprintf(stderr," there=");
158132451Sroberto        display_sock_in_hex(&there[which]);
159132451Sroberto        fputc('\n',stderr);
160132451Sroberto    }
161132451Sroberto
162132451Sroberto/* Allocate a local UDP socket and configure it. */
163132451Sroberto
164132451Sroberto    switch(((struct sockaddr_in *)&there[which])->sin_family) {
165132451Sroberto    case AF_INET:
166132451Sroberto	sl = sizeof(struct sockaddr_in);
167132451Sroberto	break;
168132451Sroberto#ifdef HAVE_IPV6
169132451Sroberto    case AF_INET6:
170132451Sroberto	sl = sizeof(struct sockaddr_in6);
171132451Sroberto	break;
172132451Sroberto#endif
173132451Sroberto    default:
174132451Sroberto	sl = 0;
175132451Sroberto	break;
176132451Sroberto    }
177132451Sroberto    errno = 0;
178132451Sroberto    if ((descriptors[which] = socket(here[which].ss_family,SOCK_DGRAM,0)) < 0
179132451Sroberto	|| bind(descriptors[which],(struct sockaddr *)&here[which], sl) < 0)
180132451Sroberto        fatal(1,"unable to allocate socket for NTP",NULL);
181132451Sroberto}
182132451Sroberto
183132451Sroberto#else
184132451Sroberto
185132451Srobertovoid open_socket (int which, char *hostname, int timespan) {
186132451Sroberto
187132451Sroberto/* Locate the specified NTP server, set up a couple of addresses and open a
188132451Srobertosocket. */
189132451Sroberto
190132451Sroberto    int port, k;
191182007Sroberto    struct in_addr address, anywhere;
192132451Sroberto
193132451Sroberto/* Initialise and find out the server and port number.  Note that the port
194132451Srobertonumber is in network format. */
195132451Sroberto
196132451Sroberto    if (initial) for (k = 0; k < MAX_SOCKETS; ++k) descriptors[k] = -1;
197132451Sroberto    initial = 0;
198132451Sroberto    if (which < 0 || which >= MAX_SOCKETS || descriptors[which] >= 0)
199132451Sroberto        fatal(0,"socket index out of range or already open",NULL);
200132451Sroberto    if (verbose > 2) fprintf(stderr,"Looking for the socket addresses\n");
201182007Sroberto    find_address(&address,&anywhere,&port,hostname,timespan);
202132451Sroberto    if (verbose > 2) {
203132451Sroberto        fprintf(stderr,"Internet address: address=");
204132451Sroberto        display_in_hex(&address,sizeof(struct in_addr));
205132451Sroberto        fprintf(stderr," anywhere=");
206132451Sroberto        display_in_hex(&anywhere,sizeof(struct in_addr));
207132451Sroberto        fputc('\n',stderr);
208132451Sroberto    }
209132451Sroberto
210182007Sroberto/* Set up our own and the target addresses. */
211132451Sroberto
212132451Sroberto    memset(&here[which],0,sizeof(struct sockaddr_in));
213132451Sroberto    here[which].sin_family = AF_INET;
214132451Sroberto    here[which].sin_port =
215182007Sroberto        (operation == op_listen || !unprivport ? port : 0);
216132451Sroberto    here[which].sin_addr = anywhere;
217132451Sroberto    memset(&there[which],0,sizeof(struct sockaddr_in));
218132451Sroberto    there[which].sin_family = AF_INET;
219132451Sroberto    there[which].sin_port = port;
220182007Sroberto    there[which].sin_addr = address;
221132451Sroberto    if (verbose > 2) {
222132451Sroberto        fprintf(stderr,"Initial sockets: here=");
223132451Sroberto        display_in_hex(&here[which].sin_addr,sizeof(struct in_addr));
224132451Sroberto        fputc('/',stderr);
225132451Sroberto        display_in_hex(&here[which].sin_port,sizeof(here[which].sin_port));
226132451Sroberto        fprintf(stderr," there=");
227132451Sroberto        display_in_hex(&there[which].sin_addr,sizeof(struct in_addr));
228132451Sroberto        fputc('/',stderr);
229132451Sroberto        display_in_hex(&there[which].sin_port,sizeof(there[which].sin_port));
230132451Sroberto        fputc('\n',stderr);
231132451Sroberto    }
232132451Sroberto
233132451Sroberto/* Allocate a local UDP socket and configure it. */
234132451Sroberto
235132451Sroberto    errno = 0;
236132451Sroberto    if ((descriptors[which] = socket(AF_INET,SOCK_DGRAM,0)) < 0 ||
237132451Sroberto            bind(descriptors[which],(struct sockaddr *)&here[which],
238132451Sroberto                    sizeof(here[which]))  < 0)
239132451Sroberto        fatal(1,"unable to allocate socket for NTP",NULL);
240132451Sroberto}
241132451Sroberto
242132451Sroberto#endif
243132451Sroberto
244132451Srobertoextern void write_socket (int which, void *packet, int length) {
245132451Sroberto
246132451Sroberto/* Any errors in doing this are fatal - including blocking.  Yes, this leaves a
247132451Srobertoserver vulnerable to a denial of service attack. */
248132451Sroberto
249132451Sroberto    int k, sl;
250132451Sroberto
251132451Sroberto    switch(((struct sockaddr_in *)&there[which])->sin_family) {
252132451Sroberto    case AF_INET:
253132451Sroberto	sl = sizeof(struct sockaddr_in);
254132451Sroberto	break;
255132451Sroberto#ifdef HAVE_IPV6
256132451Sroberto    case AF_INET6:
257132451Sroberto	sl = sizeof(struct sockaddr_in6);
258132451Sroberto	break;
259132451Sroberto#endif
260132451Sroberto    default:
261132451Sroberto	sl = 0;
262132451Sroberto	break;
263132451Sroberto    }
264132451Sroberto    if (which < 0 || which >= MAX_SOCKETS || descriptors[which] < 0)
265132451Sroberto        fatal(0,"socket index out of range or not open",NULL);
266132451Sroberto    errno = 0;
267132451Sroberto    k = sendto(descriptors[which],packet,(size_t)length,0,
268132451Sroberto            (struct sockaddr *)&there[which],sl);
269132451Sroberto    if (k != length) fatal(1,"unable to send NTP packet",NULL);
270132451Sroberto}
271132451Sroberto
272132451Sroberto
273132451Sroberto
274132451Srobertoextern int read_socket (int which, void *packet, int length, int waiting) {
275132451Sroberto
276132451Sroberto/* Read a packet and return its length or -1 for failure.  Only incorrect
277132451Srobertolength and timeout are not fatal. */
278132451Sroberto
279132451Sroberto#ifdef HAVE_IPV6
280132451Sroberto    struct sockaddr_storage scratch, *ptr;
281132451Sroberto#else
282132451Sroberto    struct sockaddr_in scratch, *ptr;
283132451Sroberto#endif
284132451Sroberto    int n;
285132451Sroberto    int k;
286132451Sroberto
287132451Sroberto/* Under normal circumstances, set up a timeout. */
288132451Sroberto
289132451Sroberto    if (which < 0 || which >= MAX_SOCKETS || descriptors[which] < 0)
290132451Sroberto        fatal(0,"socket index out of range or not open",NULL);
291132451Sroberto    if (waiting > 0) {
292132451Sroberto        if (setjmp(jump_buffer)) {
293132451Sroberto            if (verbose > 2)
294132451Sroberto                fprintf(stderr,"Receive timed out\n");
295132451Sroberto            else if (verbose > 1)
296132451Sroberto                fprintf(stderr,"%s: receive timed out after %d seconds\n",
297132451Sroberto                    argv0,waiting);
298132451Sroberto            return -1;
299132451Sroberto        }
300132451Sroberto        errno = 0;
301132451Sroberto        if (signal(SIGALRM,jump_handler) == SIG_ERR)
302132451Sroberto            fatal(1,"unable to set up signal handler",NULL);
303132451Sroberto        alarm((unsigned int)waiting);
304132451Sroberto    }
305132451Sroberto
306132451Sroberto/* Get the packet and clear the timeout, if any.  */
307132451Sroberto
308182007Sroberto    memcpy(ptr = &scratch,&there[which],sizeof(scratch));
309132451Sroberto    n = sizeof(scratch);
310132451Sroberto    errno = 0;
311132451Sroberto    k = recvfrom(descriptors[which],packet,(size_t)length,0,
312132451Sroberto        (struct sockaddr *)ptr,&n);
313132451Sroberto    if (waiting > 0) clear_alarm();
314132451Sroberto
315132451Sroberto/* Now issue some low-level diagnostics. */
316132451Sroberto
317132451Sroberto    if (k <= 0) fatal(1,"unable to receive NTP packet from server",NULL);
318132451Sroberto    if (verbose > 2) {
319132451Sroberto        fprintf(stderr,"Packet of length %d received from ",k);
320132451Sroberto        display_sock_in_hex(ptr);
321132451Sroberto        fputc('\n',stderr);
322132451Sroberto    }
323132451Sroberto    return k;
324132451Sroberto}
325132451Sroberto
326132451Sroberto
327132451Sroberto
328132451Srobertoextern int flush_socket (int which) {
329132451Sroberto
330132451Sroberto/* Get rid of any outstanding input, because it may have been hanging around
331132451Srobertofor a while.  Ignore packet length oddities and return the number of packets
332132451Srobertoskipped. */
333132451Sroberto
334132451Sroberto#ifdef HAVE_IPV6
335132451Sroberto    struct sockaddr_storage scratch;
336132451Sroberto#else
337132451Sroberto    struct sockaddr_in scratch;
338132451Sroberto#endif
339132451Sroberto    int n;
340132451Sroberto    char buffer[256];
341132451Sroberto    int flags, count = 0, total = 0, k;
342132451Sroberto
343132451Sroberto/* The code is the obvious. */
344132451Sroberto
345132451Sroberto    if (which < 0 || which >= MAX_SOCKETS || descriptors[which] < 0)
346132451Sroberto        fatal(0,"socket index out of range or not open",NULL);
347132451Sroberto    if (verbose > 2) fprintf(stderr,"Flushing outstanding packets\n");
348132451Sroberto    errno = 0;
349132451Sroberto    if ((flags = fcntl(descriptors[which],F_GETFL,0)) < 0 ||
350132451Sroberto            fcntl(descriptors[which],F_SETFL,flags|O_NONBLOCK) == -1)
351132451Sroberto        fatal(1,"unable to set non-blocking mode",NULL);
352132451Sroberto    while (1) {
353132451Sroberto        n = sizeof(scratch);
354132451Sroberto        errno = 0;
355132451Sroberto        k = recvfrom(descriptors[which],buffer,256,0,
356132451Sroberto            (struct sockaddr *)&scratch,&n);
357132451Sroberto        if (k < 0) {
358132451Sroberto            if (errno == EAGAIN || errno == EWOULDBLOCK) break;
359132451Sroberto            fatal(1,"unable to flush socket",NULL);
360132451Sroberto        }
361132451Sroberto        ++count;
362132451Sroberto        total += k;
363132451Sroberto    }
364132451Sroberto    errno = 0;
365132451Sroberto    if (fcntl(descriptors[which],F_SETFL,flags) == -1)
366132451Sroberto        fatal(1,"unable to restore blocking mode",NULL);
367132451Sroberto    if (verbose > 2)
368132451Sroberto        fprintf(stderr,"Flushed %d packets totalling %d bytes\n",count,total);
369132451Sroberto    return count;
370132451Sroberto}
371132451Sroberto
372132451Sroberto
373132451Sroberto
374132451Srobertoextern void close_socket (int which) {
375132451Sroberto
376132451Sroberto/* There is little point in shielding this with a timeout, because any hangs
377132451Srobertoare unlikely to be interruptible.  It can get called when the sockets haven't
378132451Srobertobeen opened, so ignore that case. */
379132451Sroberto
380132451Sroberto    if (which < 0 || which >= MAX_SOCKETS)
381132451Sroberto        fatal(0,"socket index out of range",NULL);
382132451Sroberto    if (descriptors[which] < 0) return;
383132451Sroberto    errno = 0;
384132451Sroberto    if (close(descriptors[which])) fatal(1,"unable to close NTP socket",NULL);
385132451Sroberto}
386