1: #include <config.h>
2: #include "networking.h"
3:
4: char adr_buf[INET6_ADDRSTRLEN];
5:
6:
7: /* resolve_hosts consumes an array of hostnames/addresses and its length, stores a pointer
8: * to the array with the resolved hosts in res and returns the size of the array res.
9: * pref_family enforces IPv4 or IPv6 depending on commandline options and system
10: * capability. If pref_family is NULL or PF_UNSPEC any compatible family will be accepted.
11: * Check here: Probably getaddrinfo() can do without ISC's IPv6 availability check?
12: */
13: int
14: resolve_hosts (
15: const char **hosts,
16: int hostc,
17: struct addrinfo ***res,
18: int pref_family
19: )
20: {
21: register unsigned int a;
22: unsigned int resc;
23: struct addrinfo **tres;
24:
25: if (hostc < 1 || NULL == res)
26: return 0;
27:
28: tres = emalloc(sizeof(struct addrinfo *) * hostc);
29: for (a = 0, resc = 0; a < hostc; a++) {
30: struct addrinfo hints;
31: int error;
32:
33: tres[resc] = NULL;
34: #ifdef DEBUG
35: printf("sntp resolve_hosts: Starting host resolution for %s...\n", hosts[a]);
36: #endif
37: memset(&hints, 0, sizeof(hints));
38: if (AF_UNSPEC == pref_family)
39: hints.ai_family = PF_UNSPEC;
40: else
41: hints.ai_family = pref_family;
42: hints.ai_socktype = SOCK_DGRAM;
43: error = getaddrinfo(hosts[a], "123", &hints, &tres[resc]);
44: if (error) {
45: msyslog(LOG_DEBUG, "Error looking up %s%s: %s",
46: (AF_UNSPEC == hints.ai_family)
47: ? ""
48: : (AF_INET == hints.ai_family)
49: ? "(A) "
50: : "(AAAA) ",
51: hosts[a], gai_strerror(error));
52: } else {
53: #ifdef DEBUG
54: for (dres = tres[resc]; dres; dres = dres->ai_next) {
55: getnameinfo(dres->ai_addr, dres->ai_addrlen, adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
56: STDLINE
57: printf("Resolv No.: %i Result of getaddrinfo for %s:\n", resc, hosts[a]);
58: printf("socktype: %i ", dres->ai_socktype);
59: printf("protocol: %i ", dres->ai_protocol);
60: printf("Prefered socktype: %i IP: %s\n", dres->ai_socktype, adr_buf);
61: STDLINE
62: }
63: #endif
64: resc++;
65: }
66: }
67:
68: if (resc)
69: *res = realloc(tres, sizeof(struct addrinfo *) * resc);
70: else {
71: free(tres);
72: *res = NULL;
73: }
74: return resc;
75: }
76:
77: /* Creates a socket and returns. */
78: void
79: create_socket (
80: SOCKET *rsock,
81: sockaddr_u *dest
82: )
83: {
84: *rsock = socket(AF(dest), SOCK_DGRAM, 0);
85:
86: if (-1 == *rsock && ENABLED_OPT(NORMALVERBOSE))
87: printf("Failed to create UDP socket with family %d\n", AF(dest));
88: }
89:
90: /* Send a packet */
91: void
92: sendpkt (
93: SOCKET rsock,
94: sockaddr_u *dest,
95: struct pkt *pkt,
96: int len
97: )
98: {
99: int cc;
100:
101: #ifdef DEBUG
102: printf("sntp sendpkt: Packet data:\n");
103: pkt_output(pkt, len, stdout);
104: #endif
105:
106: if (ENABLED_OPT(NORMALVERBOSE)) {
107: getnameinfo(&dest->sa, SOCKLEN(dest), adr_buf, sizeof(adr_buf), NULL, 0, NI_NUMERICHOST);
108: printf("sntp sendpkt: Sending packet to %s... ", adr_buf);
109: }
110:
111: cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, SOCKLEN(dest));
112: if (cc == SOCKET_ERROR) {
113: #ifdef DEBUG
114: printf("\n sntp sendpkt: Socket error: %i. Couldn't send packet!\n", cc);
115: #endif
116: if (errno != EWOULDBLOCK && errno != ENOBUFS) {
117: /* oh well */
118: }
119: } else if (ENABLED_OPT(NORMALVERBOSE)) {
120: printf("Packet sent.\n");
121: }
122: }
123:
124: /* Receive raw data */
125: int
126: recvdata(
127: SOCKET rsock,
128: sockaddr_u *sender,
129: char *rdata,
130: int rdata_length
131: )
132: {
133: GETSOCKNAME_SOCKLEN_TYPE slen;
134: int recvc;
135:
136: #ifdef DEBUG
137: printf("sntp recvdata: Trying to receive data from...\n");
138: #endif
139: slen = sizeof(*sender);
140: recvc = recvfrom(rsock, rdata, rdata_length, 0,
141: &sender->sa, &slen);
142: #ifdef DEBUG
143: if (recvc > 0) {
144: printf("Received %d bytes from %s:\n", recvc, stoa(sender));
145: pkt_output((struct pkt *) rdata, recvc, stdout);
146: } else {
147: saved_errno = errno;
148: printf("recvfrom error %d (%s)\n", errno, strerror(errno));
149: errno = saved_errno;
150: }
151: #endif
152: return recvc;
153: }
154:
155: /* Receive data from broadcast. Couldn't finish that. Need to do some digging
156: * here, especially for protocol independence and IPv6 multicast */
157: int
158: recv_bcst_data (
159: SOCKET rsock,
160: char *rdata,
161: int rdata_len,
162: sockaddr_u *sas,
163: sockaddr_u *ras
164: )
165: {
166: char *buf;
167: int btrue = 1;
168: int recv_bytes = 0;
169: int rdy_socks;
170: GETSOCKNAME_SOCKLEN_TYPE ss_len;
171: struct timeval timeout_tv;
172: fd_set bcst_fd;
173: #ifdef MCAST
174: struct ip_mreq mdevadr;
175: TYPEOF_IP_MULTICAST_LOOP mtrue = 1;
176: #endif
177: #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
178: struct ipv6_mreq mdevadr6;
179: #endif
180:
181: setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
182: if (IS_IPV4(sas)) {
183: if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
184: if (ENABLED_OPT(NORMALVERBOSE))
185: printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n",
186: stoa(sas), SRCPORT(sas));
187: }
188:
189: #ifdef MCAST
190: if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) {
191: /* some error message regarding setting up multicast loop */
192: return BROADCAST_FAILED;
193: }
194: mdevadr.imr_multiaddr.s_addr = NSRCADR(sas);
195: mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
196: if (mdevadr.imr_multiaddr.s_addr == -1) {
197: if (ENABLED_OPT(NORMALVERBOSE)) {
198: printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n",
199: stoa(sas), SRCPORT(sas));
200: }
201: return BROADCAST_FAILED;
202: }
203: if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
204: if (ENABLED_OPT(NORMALVERBOSE)) {
205: buf = ss_to_str(sas);
206: printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
207: free(buf);
208: }
209: }
210: #endif /* MCAST */
211: }
212: #ifdef ISC_PLATFORM_HAVEIPV6
213: else if (IS_IPV6(sas)) {
214: if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
215: if (ENABLED_OPT(NORMALVERBOSE))
216: printf("sntp recv_bcst_data: Couldn't bind() address.\n");
217: }
218: #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
219: if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
220: /* some error message regarding setting up multicast loop */
221: return BROADCAST_FAILED;
222: }
223: memset(&mdevadr6, 0, sizeof(mdevadr6));
224: mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas);
225: if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) {
226: if (ENABLED_OPT(NORMALVERBOSE)) {
227: buf = ss_to_str(sas);
228: printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
229: free(buf);
230: }
231: return BROADCAST_FAILED;
232: }
233: if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
234: &mdevadr6, sizeof(mdevadr6)) < 0) {
235: if (ENABLED_OPT(NORMALVERBOSE)) {
236: buf = ss_to_str(sas);
237: printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
238: free(buf);
239: }
240: }
241: #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
242: }
243: #endif /* ISC_PLATFORM_HAVEIPV6 */
244: FD_ZERO(&bcst_fd);
245: FD_SET(rsock, &bcst_fd);
246: if (ENABLED_OPT(TIMEOUT))
247: timeout_tv.tv_sec = (int) OPT_ARG(TIMEOUT);
248: else
249: timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
250: timeout_tv.tv_usec = 0;
251: rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv);
252: switch (rdy_socks) {
253: case -1:
254: if (ENABLED_OPT(NORMALVERBOSE))
255: perror("sntp recv_bcst_data: select()");
256: return BROADCAST_FAILED;
257: break;
258: case 0:
259: if (ENABLED_OPT(NORMALVERBOSE))
260: printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n",
261: (unsigned)timeout_tv.tv_sec);
262: return BROADCAST_FAILED;
263: break;
264: default:
265: ss_len = sizeof(*ras);
266: recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
267: break;
268: }
269: if (recv_bytes == -1) {
270: if (ENABLED_OPT(NORMALVERBOSE))
271: perror("sntp recv_bcst_data: recvfrom:");
272: recv_bytes = BROADCAST_FAILED;
273: }
274: #ifdef MCAST
275: if (IS_IPV4(sas))
276: setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
277: #endif
278: #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
279: if (IS_IPV6(sas))
280: setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
281: #endif
282: return recv_bytes;
283: }
284:
285: int
286: process_pkt (
287: struct pkt *rpkt,
288: sockaddr_u *sas,
289: int pkt_len,
290: int mode,
291: struct pkt *spkt,
292: char * func_name
293: )
294: {
295: unsigned int key_id = 0;
296: struct key *pkt_key = NULL;
297: int is_authentic = 0;
298: unsigned int exten_words, exten_words_used = 0;
299: int mac_size;
300: /*
301: * Parse the extension field if present. We figure out whether
302: * an extension field is present by measuring the MAC size. If
303: * the number of words following the packet header is 0, no MAC
304: * is present and the packet is not authenticated. If 1, the
305: * packet is a crypto-NAK; if 3, the packet is authenticated
306: * with DES; if 5, the packet is authenticated with MD5; if 6,
307: * the packet is authenticated with SHA. If 2 or 4, the packet
308: * is a runt and discarded forthwith. If greater than 6, an
309: * extension field is present, so we subtract the length of the
310: * field and go around again.
311: */
312: if (pkt_len < LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
313: unusable:
314: if (ENABLED_OPT(NORMALVERBOSE))
315: printf("sntp %s: Funny packet length: %i. Discarding package.\n", func_name, pkt_len);
316: return PACKET_UNUSEABLE;
317: }
318: /* skip past the extensions, if any */
319: exten_words = ((unsigned)pkt_len - LEN_PKT_NOMAC) >> 2;
320: while (exten_words > 6) {
321: unsigned int exten_len;
322: exten_len = ntohl(rpkt->exten[exten_words_used]) & 0xffff;
323: exten_len = (exten_len + 7) >> 2; /* convert to words, add 1 */
324: if (exten_len > exten_words || exten_len < 5)
325: goto unusable;
326: exten_words -= exten_len;
327: exten_words_used += exten_len;
328: }
329:
330: switch (exten_words) {
331: case 1:
332: key_id = ntohl(rpkt->exten[exten_words_used]);
333: printf("Crypto NAK = 0x%08x\n", key_id);
334: break;
335: case 5:
336: case 6:
337: /* Look for the key used by the server in the specified keyfile
338: * and if existent, fetch it or else leave the pointer untouched */
339: key_id = ntohl(rpkt->exten[exten_words_used]);
340: get_key(key_id, &pkt_key);
341: if (!pkt_key) {
342: printf("unrecognized key ID = 0x%08x\n", key_id);
343: break;
344: }
345: /* Seems like we've got a key with matching keyid */
346: /* Generate a md5sum of the packet with the key from our keyfile
347: * and compare those md5sums */
348: mac_size = exten_words << 2;
349: if (!auth_md5((char *)rpkt, pkt_len - mac_size, mac_size - 4, pkt_key)) {
350: break;
351: }
352: /* Yay! Things worked out! */
353: if (ENABLED_OPT(NORMALVERBOSE)) {
354: char *hostname = ss_to_str(sas);
355: printf("sntp %s: packet received from %s successfully authenticated using key id %i.\n",
356: func_name, hostname, key_id);
357: free(hostname);
358: }
359: is_authentic = 1;
360: break;
361: case 0:
362: break;
363: default:
364: goto unusable;
365: break;
366: }
367: if (!is_authentic) {
368: if (ENABLED_OPT(AUTHENTICATION)) {
369: /* We want a authenticated packet */
370: if (ENABLED_OPT(NORMALVERBOSE)) {
371: char *hostname = ss_to_str(sas);
372: printf("sntp %s: packet received from %s is not authentic. Will discard it.\n",
373: func_name, hostname);
374: free(hostname);
375: }
376: return SERVER_AUTH_FAIL;
377: }
378: /* We don't know if the user wanted authentication so let's
379: * use it anyways */
380: if (ENABLED_OPT(NORMALVERBOSE)) {
381: char *hostname = ss_to_str(sas);
382: printf("sntp %s: packet received from %s is not authentic. Authentication not enforced.\n",
383: func_name, hostname);
384: free(hostname);
385: }
386: }
387: /* Check for server's ntp version */
388: if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
389: PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
390: if (ENABLED_OPT(NORMALVERBOSE))
391: printf("sntp %s: Packet shows wrong version (%i)\n",
392: func_name, PKT_VERSION(rpkt->li_vn_mode));
393: return SERVER_UNUSEABLE;
394: }
395: /* We want a server to sync with */
396: if (PKT_MODE(rpkt->li_vn_mode) != mode &&
397: PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
398: if (ENABLED_OPT(NORMALVERBOSE))
399: printf("sntp %s: mode %d stratum %i\n", func_name,
400: PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
401: return SERVER_UNUSEABLE;
402: }
403: /* Stratum is unspecified (0) check what's going on */
404: if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
405: char *ref_char;
406: if (ENABLED_OPT(NORMALVERBOSE))
407: printf("sntp %s: Stratum unspecified, going to check for KOD (stratum: %i)\n",
408: func_name, rpkt->stratum);
409: ref_char = (char *) &rpkt->refid;
410: if (ENABLED_OPT(NORMALVERBOSE))
411: printf("sntp %s: Packet refid: %c%c%c%c\n", func_name,
412: ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
413: /* If it's a KOD packet we'll just use the KOD information */
414: if (ref_char[0] != 'X') {
415: if (strncmp(ref_char, "DENY", 4) == 0)
416: return KOD_DEMOBILIZE;
417: if (strncmp(ref_char, "RSTR", 4) == 0)
418: return KOD_DEMOBILIZE;
419: if (strncmp(ref_char, "RATE", 4) == 0)
420: return KOD_RATE;
421: /* There are other interesting kiss codes which might be interesting for authentication */
422: }
423: }
424: /* If the server is not synced it's not really useable for us */
425: if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
426: if (ENABLED_OPT(NORMALVERBOSE))
427: printf("sntp %s: Server not in sync, skipping this server\n", func_name);
428: return SERVER_UNUSEABLE;
429: }
430:
431: /*
432: * Decode the org timestamp and make sure we're getting a response
433: * to our last request, but only if we're not in broadcast mode.
434: */
435: #ifdef DEBUG
436: printf("rpkt->org:\n");
437: l_fp_output(&rpkt->org, stdout);
438: printf("spkt->xmt:\n");
439: l_fp_output(&spkt->xmt, stdout);
440: #endif
441: if (mode != MODE_BROADCAST && !L_ISEQU(&rpkt->org, &spkt->xmt)) {
442: if (ENABLED_OPT(NORMALVERBOSE))
443: printf("sntp process_pkt: pkt.org and peer.xmt differ\n");
444: return PACKET_UNUSEABLE;
445: }
446:
447: return pkt_len;
448: }
449:
450: int
451: recv_bcst_pkt (
452: SOCKET rsock,
453: struct pkt *rpkt,
454: unsigned int rsize,
455: sockaddr_u *sas
456: )
457: {
458: sockaddr_u sender;
459: int pkt_len = recv_bcst_data(rsock, (char *)rpkt, rsize, sas, &sender);
460: if (pkt_len < 0) {
461: return BROADCAST_FAILED;
462: }
463: pkt_len = process_pkt(rpkt, sas, pkt_len, MODE_BROADCAST, NULL, "recv_bcst_pkt");
464: return pkt_len;
465: }
466:
467: /* Fetch data, check if it's data for us and whether it's useable or not. If not, return
468: * a failure code so we can delete this server from our list and continue with another one.
469: */
470: int
471: recvpkt (
472: SOCKET rsock,
473: struct pkt *rpkt, /* received packet (response) */
474: unsigned int rsize, /* size of rpkt buffer */
475: struct pkt *spkt /* sent packet (request) */
476: )
477: {
478: int rdy_socks;
479: int pkt_len;
480: sockaddr_u sender;
481: struct timeval timeout_tv;
482: fd_set recv_fd;
483:
484: FD_ZERO(&recv_fd);
485: FD_SET(rsock, &recv_fd);
486: if (ENABLED_OPT(TIMEOUT))
487: timeout_tv.tv_sec = (int) OPT_ARG(TIMEOUT);
488: else
489: timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
490: timeout_tv.tv_usec = 0;
491: rdy_socks = select(rsock + 1, &recv_fd, 0, 0, &timeout_tv);
492: switch (rdy_socks) {
493: case -1:
494: if (ENABLED_OPT(NORMALVERBOSE))
495: perror("sntp recvpkt: select()");
496: return PACKET_UNUSEABLE;
497: break;
498: case 0:
499: if (ENABLED_OPT(NORMALVERBOSE))
500: printf("sntp recvpkt: select() reached timeout (%u sec), aborting.\n",
501: (unsigned)timeout_tv.tv_sec);
502: return PACKET_UNUSEABLE;
503: break;
504: default:
505: break;
506: }
507: pkt_len = recvdata(rsock, &sender, (char *)rpkt, rsize);
508: if (pkt_len > 0)
509: pkt_len = process_pkt(rpkt, &sender, pkt_len, MODE_SERVER, spkt, "recvpkt");
510:
511: return pkt_len;
512: }
513:
514: /*
515: * is_reachable - check to see if we have a route to given destination
516: */
517: int
518: is_reachable (
519: struct addrinfo *dst
520: )
521: {
522: SOCKET sockfd = socket(dst->ai_family, SOCK_DGRAM, 0);
523:
524: if (-1 == sockfd) {
525: #ifdef DEBUG
526: printf("is_reachable: Couldn't create socket\n");
527: #endif
528: return 0;
529: }
530: if (connect(sockfd, dst->ai_addr, SOCKLEN((sockaddr_u *)dst->ai_addr))) {
531: closesocket(sockfd);
532: return 0;
533: }
534: closesocket(sockfd);
535: return 1;
536: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>