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 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) { 292b15cb3dSCy Schubert msyslog(LOG_ERR, "Send to %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 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* 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) { 81*052d159aSCy Schubert nlen = ntohl(*head) & 0xffff; 82*052d159aSCy 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 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