12b15cb3dSCy Schubert #include <config.h>
22b15cb3dSCy Schubert #include "networking.h"
32b15cb3dSCy Schubert #include "ntp_debug.h"
42b15cb3dSCy Schubert
52b15cb3dSCy Schubert
62b15cb3dSCy Schubert /* Send a packet */
72b15cb3dSCy Schubert int
sendpkt(SOCKET rsock,sockaddr_u * dest,struct pkt * pkt,int len)82b15cb3dSCy Schubert sendpkt (
92b15cb3dSCy Schubert SOCKET rsock,
102b15cb3dSCy Schubert sockaddr_u *dest,
112b15cb3dSCy Schubert struct pkt *pkt,
122b15cb3dSCy Schubert int len
132b15cb3dSCy Schubert )
142b15cb3dSCy Schubert {
152b15cb3dSCy Schubert int cc;
162b15cb3dSCy Schubert
172b15cb3dSCy Schubert #ifdef DEBUG
182b15cb3dSCy Schubert if (debug > 2) {
192b15cb3dSCy Schubert printf("sntp sendpkt: Packet data:\n");
202b15cb3dSCy Schubert pkt_output(pkt, len, stdout);
212b15cb3dSCy Schubert }
222b15cb3dSCy Schubert #endif
232b15cb3dSCy Schubert TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n",
242b15cb3dSCy Schubert sptoa(dest)));
252b15cb3dSCy Schubert
262b15cb3dSCy Schubert cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa,
272b15cb3dSCy Schubert SOCKLEN(dest));
282b15cb3dSCy Schubert if (cc == SOCKET_ERROR) {
29*2d4e511cSCy Schubert msyslog(LOG_ERR, "sendpkt: sendto(%s) failed: %m",
302b15cb3dSCy Schubert sptoa(dest));
312b15cb3dSCy Schubert return FALSE;
322b15cb3dSCy Schubert }
332b15cb3dSCy Schubert TRACE(1, ("Packet sent.\n"));
342b15cb3dSCy Schubert
352b15cb3dSCy Schubert return TRUE;
362b15cb3dSCy Schubert }
372b15cb3dSCy Schubert
382b15cb3dSCy Schubert
392b15cb3dSCy Schubert /* Receive raw data */
402b15cb3dSCy Schubert int
recvdata(SOCKET rsock,sockaddr_u * sender,void * rdata,int rdata_length)412b15cb3dSCy Schubert recvdata(
422b15cb3dSCy Schubert SOCKET rsock,
432b15cb3dSCy Schubert sockaddr_u * sender,
442b15cb3dSCy Schubert void * rdata,
452b15cb3dSCy Schubert int rdata_length
462b15cb3dSCy Schubert )
472b15cb3dSCy Schubert {
482b15cb3dSCy Schubert GETSOCKNAME_SOCKLEN_TYPE slen;
492b15cb3dSCy Schubert int recvc;
502b15cb3dSCy Schubert
512b15cb3dSCy Schubert slen = sizeof(*sender);
522b15cb3dSCy Schubert recvc = recvfrom(rsock, rdata, rdata_length, 0,
532b15cb3dSCy Schubert &sender->sa, &slen);
542b15cb3dSCy Schubert if (recvc < 0)
552b15cb3dSCy Schubert return recvc;
562b15cb3dSCy Schubert #ifdef DEBUG
572b15cb3dSCy Schubert if (debug > 2) {
582b15cb3dSCy Schubert printf("Received %d bytes from %s:\n", recvc, sptoa(sender));
592b15cb3dSCy Schubert pkt_output((struct pkt *)rdata, recvc, stdout);
602b15cb3dSCy Schubert }
612b15cb3dSCy Schubert #endif
622b15cb3dSCy Schubert return recvc;
632b15cb3dSCy Schubert }
642b15cb3dSCy Schubert
652b15cb3dSCy Schubert /* Parsing from a short 'struct pkt' directly is bound to create
662b15cb3dSCy Schubert * coverity warnings. These are hard to avoid, as the formal declaration
672b15cb3dSCy Schubert * does not reflect the true layout in the presence of autokey extension
682b15cb3dSCy Schubert * fields. Parsing and skipping the extension fields of a received packet
692b15cb3dSCy Schubert * until there's only the MAC left is better done in this separate
702b15cb3dSCy Schubert * function.
712b15cb3dSCy Schubert */
722b15cb3dSCy Schubert static void*
skip_efields(u_int32 * head,u_int32 * tail)732b15cb3dSCy Schubert skip_efields(
742b15cb3dSCy Schubert u_int32 *head, /* head of extension chain */
752b15cb3dSCy Schubert u_int32 *tail /* tail/end of extension chain */
762b15cb3dSCy Schubert )
772b15cb3dSCy Schubert {
782b15cb3dSCy Schubert
792b15cb3dSCy Schubert u_int nlen; /* next extension length */
802b15cb3dSCy Schubert while ((tail - head) > 6) {
81052d159aSCy Schubert nlen = ntohl(*head) & 0xffff;
82052d159aSCy Schubert ++head;
832b15cb3dSCy Schubert nlen = (nlen + 3) >> 2;
842b15cb3dSCy Schubert if (nlen > (u_int)(tail - head) || nlen < 4)
852b15cb3dSCy Schubert return NULL; /* Blooper! Inconsistent! */
862b15cb3dSCy Schubert head += nlen;
872b15cb3dSCy Schubert }
882b15cb3dSCy Schubert return head;
892b15cb3dSCy Schubert }
902b15cb3dSCy Schubert
912b15cb3dSCy Schubert /*
922b15cb3dSCy Schubert ** Check if it's data for us and whether it's useable or not.
932b15cb3dSCy Schubert **
942b15cb3dSCy Schubert ** If not, return a failure code so we can delete this server from our list
952b15cb3dSCy Schubert ** and continue with another one.
962b15cb3dSCy Schubert */
972b15cb3dSCy Schubert int
process_pkt(struct pkt * rpkt,sockaddr_u * sender,int pkt_len,int mode,struct pkt * spkt,const char * func_name)982b15cb3dSCy Schubert process_pkt (
992b15cb3dSCy Schubert struct pkt *rpkt,
1002b15cb3dSCy Schubert sockaddr_u *sender,
1012b15cb3dSCy Schubert int pkt_len,
1022b15cb3dSCy Schubert int mode,
1032b15cb3dSCy Schubert struct pkt *spkt,
1042b15cb3dSCy Schubert const char * func_name
1052b15cb3dSCy Schubert )
1062b15cb3dSCy Schubert {
1072b15cb3dSCy Schubert u_int key_id;
1082b15cb3dSCy Schubert struct key * pkt_key;
1092b15cb3dSCy Schubert int is_authentic;
1102b15cb3dSCy Schubert int mac_size;
1112b15cb3dSCy Schubert u_int exten_len;
1122b15cb3dSCy Schubert u_int32 * exten_end;
1132b15cb3dSCy Schubert u_int32 * packet_end;
1142b15cb3dSCy Schubert l_fp sent_xmt;
1152b15cb3dSCy Schubert l_fp resp_org;
1162b15cb3dSCy Schubert
1179034852cSGleb Smirnoff // key_id = 0;
1182b15cb3dSCy Schubert pkt_key = NULL;
1192b15cb3dSCy Schubert is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;
1202b15cb3dSCy Schubert
1212b15cb3dSCy Schubert /*
1222b15cb3dSCy Schubert * Parse the extension field if present. We figure out whether
1232b15cb3dSCy Schubert * an extension field is present by measuring the MAC size. If
1242b15cb3dSCy Schubert * the number of words following the packet header is 0, no MAC
1252b15cb3dSCy Schubert * is present and the packet is not authenticated. If 1, the
1262b15cb3dSCy Schubert * packet is a crypto-NAK; if 3, the packet is authenticated
1272b15cb3dSCy Schubert * with DES; if 5, the packet is authenticated with MD5; if 6,
1282b15cb3dSCy Schubert * the packet is authenticated with SHA. If 2 or 4, the packet
1292b15cb3dSCy Schubert * is a runt and discarded forthwith. If greater than 6, an
1302b15cb3dSCy Schubert * extension field is present, so we subtract the length of the
1312b15cb3dSCy Schubert * field and go around again.
1322b15cb3dSCy Schubert */
1332b15cb3dSCy Schubert if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
1342b15cb3dSCy Schubert msyslog(LOG_ERR,
1352b15cb3dSCy Schubert "%s: Incredible packet length: %d. Discarding.",
1362b15cb3dSCy Schubert func_name, pkt_len);
1372b15cb3dSCy Schubert return PACKET_UNUSEABLE;
1382b15cb3dSCy Schubert }
13909100258SXin LI
14009100258SXin LI /* HMS: the following needs a bit of work */
1412b15cb3dSCy Schubert /* Note: pkt_len must be a multiple of 4 at this point! */
1423311ff84SXin LI packet_end = (void*)((char*)rpkt + pkt_len);
1432b15cb3dSCy Schubert exten_end = skip_efields(rpkt->exten, packet_end);
1442b15cb3dSCy Schubert if (NULL == exten_end) {
1452b15cb3dSCy Schubert msyslog(LOG_ERR,
1462b15cb3dSCy Schubert "%s: Missing extension field. Discarding.",
1472b15cb3dSCy Schubert func_name);
1482b15cb3dSCy Schubert return PACKET_UNUSEABLE;
1492b15cb3dSCy Schubert }
15009100258SXin LI
1512b15cb3dSCy Schubert /* get size of MAC in cells; can be zero */
1522b15cb3dSCy Schubert exten_len = (u_int)(packet_end - exten_end);
1532b15cb3dSCy Schubert
1542b15cb3dSCy Schubert /* deduce action required from remaining length */
1552b15cb3dSCy Schubert switch (exten_len) {
1562b15cb3dSCy Schubert
15709100258SXin LI case 0: /* no Legacy MAC */
1582b15cb3dSCy Schubert break;
1592b15cb3dSCy Schubert
1602b15cb3dSCy Schubert case 1: /* crypto NAK */
16109100258SXin LI /* Only if the keyID is 0 and there were no EFs */
1622b15cb3dSCy Schubert key_id = ntohl(*exten_end);
16309100258SXin LI printf("Crypto NAK = 0x%08x from %s\n", key_id, stoa(sender));
1642b15cb3dSCy Schubert break;
1652b15cb3dSCy Schubert
1662b15cb3dSCy Schubert case 3: /* key ID + 3DES MAC -- unsupported! */
1672b15cb3dSCy Schubert msyslog(LOG_ERR,
1682b15cb3dSCy Schubert "%s: Key ID + 3DES MAC is unsupported. Discarding.",
1692b15cb3dSCy Schubert func_name);
1702b15cb3dSCy Schubert return PACKET_UNUSEABLE;
1712b15cb3dSCy Schubert
1722b15cb3dSCy Schubert case 5: /* key ID + MD5 MAC */
1732b15cb3dSCy Schubert case 6: /* key ID + SHA MAC */
1742b15cb3dSCy Schubert /*
1752b15cb3dSCy Schubert ** Look for the key used by the server in the specified
1762b15cb3dSCy Schubert ** keyfile and if existent, fetch it or else leave the
1772b15cb3dSCy Schubert ** pointer untouched
1782b15cb3dSCy Schubert */
1792b15cb3dSCy Schubert key_id = ntohl(*exten_end);
1802b15cb3dSCy Schubert get_key(key_id, &pkt_key);
1812b15cb3dSCy Schubert if (!pkt_key) {
1822b15cb3dSCy Schubert printf("unrecognized key ID = 0x%08x\n", key_id);
1832b15cb3dSCy Schubert break;
1842b15cb3dSCy Schubert }
1852b15cb3dSCy Schubert /*
1862b15cb3dSCy Schubert ** Seems like we've got a key with matching keyid.
1872b15cb3dSCy Schubert **
1882b15cb3dSCy Schubert ** Generate a md5sum of the packet with the key from our
1892b15cb3dSCy Schubert ** keyfile and compare those md5sums.
1902b15cb3dSCy Schubert */
1912b15cb3dSCy Schubert mac_size = exten_len << 2;
19268ba7e87SXin LI if (!auth_md5(rpkt, pkt_len - mac_size,
1932b15cb3dSCy Schubert mac_size - 4, pkt_key)) {
1942b15cb3dSCy Schubert is_authentic = FALSE;
1952b15cb3dSCy Schubert break;
1962b15cb3dSCy Schubert }
1972b15cb3dSCy Schubert /* Yay! Things worked out! */
1982b15cb3dSCy Schubert is_authentic = TRUE;
1992b15cb3dSCy Schubert TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
2002b15cb3dSCy Schubert func_name, stoa(sender), key_id));
2012b15cb3dSCy Schubert break;
2022b15cb3dSCy Schubert
2032b15cb3dSCy Schubert default:
2042b15cb3dSCy Schubert msyslog(LOG_ERR,
2052b15cb3dSCy Schubert "%s: Unexpected extension length: %d. Discarding.",
2062b15cb3dSCy Schubert func_name, exten_len);
2072b15cb3dSCy Schubert return PACKET_UNUSEABLE;
2082b15cb3dSCy Schubert }
2092b15cb3dSCy Schubert
2102b15cb3dSCy Schubert switch (is_authentic) {
2112b15cb3dSCy Schubert
2122b15cb3dSCy Schubert case -1: /* unknown */
2132b15cb3dSCy Schubert break;
2142b15cb3dSCy Schubert
2152b15cb3dSCy Schubert case 0: /* not authentic */
2162b15cb3dSCy Schubert return SERVER_AUTH_FAIL;
2172b15cb3dSCy Schubert break;
2182b15cb3dSCy Schubert
2192b15cb3dSCy Schubert case 1: /* authentic */
2202b15cb3dSCy Schubert break;
2212b15cb3dSCy Schubert
2222b15cb3dSCy Schubert default: /* error */
2232b15cb3dSCy Schubert break;
2242b15cb3dSCy Schubert }
2252b15cb3dSCy Schubert
2262b15cb3dSCy Schubert /* Check for server's ntp version */
2272b15cb3dSCy Schubert if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
2282b15cb3dSCy Schubert PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
2292b15cb3dSCy Schubert msyslog(LOG_ERR,
2302b15cb3dSCy Schubert "%s: Packet shows wrong version (%d)",
2312b15cb3dSCy Schubert func_name, PKT_VERSION(rpkt->li_vn_mode));
2322b15cb3dSCy Schubert return SERVER_UNUSEABLE;
2332b15cb3dSCy Schubert }
2342b15cb3dSCy Schubert /* We want a server to sync with */
2352b15cb3dSCy Schubert if (PKT_MODE(rpkt->li_vn_mode) != mode &&
2362b15cb3dSCy Schubert PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
2372b15cb3dSCy Schubert msyslog(LOG_ERR,
2382b15cb3dSCy Schubert "%s: mode %d stratum %d", func_name,
2392b15cb3dSCy Schubert PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
2402b15cb3dSCy Schubert return SERVER_UNUSEABLE;
2412b15cb3dSCy Schubert }
2422b15cb3dSCy Schubert /* Stratum is unspecified (0) check what's going on */
2432b15cb3dSCy Schubert if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
2442b15cb3dSCy Schubert char *ref_char;
2452b15cb3dSCy Schubert
2462b15cb3dSCy Schubert TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n",
2472b15cb3dSCy Schubert func_name, rpkt->stratum));
2482b15cb3dSCy Schubert ref_char = (char *) &rpkt->refid;
2492b15cb3dSCy Schubert TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name,
2502b15cb3dSCy Schubert ref_char[0], ref_char[1], ref_char[2], ref_char[3]));
2512b15cb3dSCy Schubert /* If it's a KOD packet we'll just use the KOD information */
2522b15cb3dSCy Schubert if (ref_char[0] != 'X') {
2532b15cb3dSCy Schubert if (strncmp(ref_char, "DENY", 4) == 0)
2542b15cb3dSCy Schubert return KOD_DEMOBILIZE;
2552b15cb3dSCy Schubert if (strncmp(ref_char, "RSTR", 4) == 0)
2562b15cb3dSCy Schubert return KOD_DEMOBILIZE;
2572b15cb3dSCy Schubert if (strncmp(ref_char, "RATE", 4) == 0)
2582b15cb3dSCy Schubert return KOD_RATE;
2592b15cb3dSCy Schubert /*
2602b15cb3dSCy Schubert ** There are other interesting kiss codes which
2612b15cb3dSCy Schubert ** might be interesting for authentication.
2622b15cb3dSCy Schubert */
2632b15cb3dSCy Schubert }
2642b15cb3dSCy Schubert }
2652b15cb3dSCy Schubert /* If the server is not synced it's not really useable for us */
2662b15cb3dSCy Schubert if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
2672b15cb3dSCy Schubert msyslog(LOG_ERR,
2682b15cb3dSCy Schubert "%s: %s not in sync, skipping this server",
2692b15cb3dSCy Schubert func_name, stoa(sender));
2702b15cb3dSCy Schubert return SERVER_UNUSEABLE;
2712b15cb3dSCy Schubert }
2722b15cb3dSCy Schubert
2732b15cb3dSCy Schubert /*
2742b15cb3dSCy Schubert * Decode the org timestamp and make sure we're getting a response
2752b15cb3dSCy Schubert * to our last request, but only if we're not in broadcast mode.
2762b15cb3dSCy Schubert */
2772b15cb3dSCy Schubert if (MODE_BROADCAST == mode)
2782b15cb3dSCy Schubert return pkt_len;
2792b15cb3dSCy Schubert
2802b15cb3dSCy Schubert if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
2812b15cb3dSCy Schubert NTOHL_FP(&rpkt->org, &resp_org);
2822b15cb3dSCy Schubert NTOHL_FP(&spkt->xmt, &sent_xmt);
2832b15cb3dSCy Schubert msyslog(LOG_ERR,
2842b15cb3dSCy Schubert "%s response org expected to match sent xmt",
2852b15cb3dSCy Schubert stoa(sender));
2862b15cb3dSCy Schubert msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
2872b15cb3dSCy Schubert msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
2882b15cb3dSCy Schubert return PACKET_UNUSEABLE;
2892b15cb3dSCy Schubert }
2902b15cb3dSCy Schubert
2912b15cb3dSCy Schubert return pkt_len;
2922b15cb3dSCy Schubert }
293