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) { 812b15cb3dSCy Schubert nlen = ntohl(*head++) & 0xffff; 822b15cb3dSCy Schubert nlen = (nlen + 3) >> 2; 832b15cb3dSCy Schubert if (nlen > (u_int)(tail - head) || nlen < 4) 842b15cb3dSCy Schubert return NULL; /* Blooper! Inconsistent! */ 852b15cb3dSCy Schubert head += nlen; 862b15cb3dSCy Schubert } 872b15cb3dSCy Schubert return head; 882b15cb3dSCy Schubert } 892b15cb3dSCy Schubert 902b15cb3dSCy Schubert /* 912b15cb3dSCy Schubert ** Check if it's data for us and whether it's useable or not. 922b15cb3dSCy Schubert ** 932b15cb3dSCy Schubert ** If not, return a failure code so we can delete this server from our list 942b15cb3dSCy Schubert ** and continue with another one. 952b15cb3dSCy Schubert */ 962b15cb3dSCy Schubert int 972b15cb3dSCy Schubert process_pkt ( 982b15cb3dSCy Schubert struct pkt *rpkt, 992b15cb3dSCy Schubert sockaddr_u *sender, 1002b15cb3dSCy Schubert int pkt_len, 1012b15cb3dSCy Schubert int mode, 1022b15cb3dSCy Schubert struct pkt *spkt, 1032b15cb3dSCy Schubert const char * func_name 1042b15cb3dSCy Schubert ) 1052b15cb3dSCy Schubert { 1062b15cb3dSCy Schubert u_int key_id; 1072b15cb3dSCy Schubert struct key * pkt_key; 1082b15cb3dSCy Schubert int is_authentic; 1092b15cb3dSCy Schubert int mac_size; 1102b15cb3dSCy Schubert u_int exten_len; 1112b15cb3dSCy Schubert u_int32 * exten_end; 1122b15cb3dSCy Schubert u_int32 * packet_end; 1132b15cb3dSCy Schubert l_fp sent_xmt; 1142b15cb3dSCy Schubert l_fp resp_org; 1152b15cb3dSCy Schubert 116*9034852cSGleb Smirnoff // key_id = 0; 1172b15cb3dSCy Schubert pkt_key = NULL; 1182b15cb3dSCy Schubert is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1; 1192b15cb3dSCy Schubert 1202b15cb3dSCy Schubert /* 1212b15cb3dSCy Schubert * Parse the extension field if present. We figure out whether 1222b15cb3dSCy Schubert * an extension field is present by measuring the MAC size. If 1232b15cb3dSCy Schubert * the number of words following the packet header is 0, no MAC 1242b15cb3dSCy Schubert * is present and the packet is not authenticated. If 1, the 1252b15cb3dSCy Schubert * packet is a crypto-NAK; if 3, the packet is authenticated 1262b15cb3dSCy Schubert * with DES; if 5, the packet is authenticated with MD5; if 6, 1272b15cb3dSCy Schubert * the packet is authenticated with SHA. If 2 or 4, the packet 1282b15cb3dSCy Schubert * is a runt and discarded forthwith. If greater than 6, an 1292b15cb3dSCy Schubert * extension field is present, so we subtract the length of the 1302b15cb3dSCy Schubert * field and go around again. 1312b15cb3dSCy Schubert */ 1322b15cb3dSCy Schubert if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) { 1332b15cb3dSCy Schubert msyslog(LOG_ERR, 1342b15cb3dSCy Schubert "%s: Incredible packet length: %d. Discarding.", 1352b15cb3dSCy Schubert func_name, pkt_len); 1362b15cb3dSCy Schubert return PACKET_UNUSEABLE; 1372b15cb3dSCy Schubert } 1382b15cb3dSCy Schubert /* Note: pkt_len must be a multiple of 4 at this point! */ 1392b15cb3dSCy Schubert packet_end = (u_int32*)((char*)rpkt + pkt_len); 1402b15cb3dSCy Schubert exten_end = skip_efields(rpkt->exten, packet_end); 1412b15cb3dSCy Schubert if (NULL == exten_end) { 1422b15cb3dSCy Schubert msyslog(LOG_ERR, 1432b15cb3dSCy Schubert "%s: Missing extension field. Discarding.", 1442b15cb3dSCy Schubert func_name); 1452b15cb3dSCy Schubert return PACKET_UNUSEABLE; 1462b15cb3dSCy Schubert } 1472b15cb3dSCy Schubert /* get size of MAC in cells; can be zero */ 1482b15cb3dSCy Schubert exten_len = (u_int)(packet_end - exten_end); 1492b15cb3dSCy Schubert 1502b15cb3dSCy Schubert /* deduce action required from remaining length */ 1512b15cb3dSCy Schubert switch (exten_len) { 1522b15cb3dSCy Schubert 1532b15cb3dSCy Schubert case 0: /* no MAC at all */ 1542b15cb3dSCy Schubert break; 1552b15cb3dSCy Schubert 1562b15cb3dSCy Schubert case 1: /* crypto NAK */ 1572b15cb3dSCy Schubert key_id = ntohl(*exten_end); 1582b15cb3dSCy Schubert printf("Crypto NAK = 0x%08x\n", key_id); 1592b15cb3dSCy Schubert break; 1602b15cb3dSCy Schubert 1612b15cb3dSCy Schubert case 3: /* key ID + 3DES MAC -- unsupported! */ 1622b15cb3dSCy Schubert msyslog(LOG_ERR, 1632b15cb3dSCy Schubert "%s: Key ID + 3DES MAC is unsupported. Discarding.", 1642b15cb3dSCy Schubert func_name); 1652b15cb3dSCy Schubert return PACKET_UNUSEABLE; 1662b15cb3dSCy Schubert 1672b15cb3dSCy Schubert case 5: /* key ID + MD5 MAC */ 1682b15cb3dSCy Schubert case 6: /* key ID + SHA MAC */ 1692b15cb3dSCy Schubert /* 1702b15cb3dSCy Schubert ** Look for the key used by the server in the specified 1712b15cb3dSCy Schubert ** keyfile and if existent, fetch it or else leave the 1722b15cb3dSCy Schubert ** pointer untouched 1732b15cb3dSCy Schubert */ 1742b15cb3dSCy Schubert key_id = ntohl(*exten_end); 1752b15cb3dSCy Schubert get_key(key_id, &pkt_key); 1762b15cb3dSCy Schubert if (!pkt_key) { 1772b15cb3dSCy Schubert printf("unrecognized key ID = 0x%08x\n", key_id); 1782b15cb3dSCy Schubert break; 1792b15cb3dSCy Schubert } 1802b15cb3dSCy Schubert /* 1812b15cb3dSCy Schubert ** Seems like we've got a key with matching keyid. 1822b15cb3dSCy Schubert ** 1832b15cb3dSCy Schubert ** Generate a md5sum of the packet with the key from our 1842b15cb3dSCy Schubert ** keyfile and compare those md5sums. 1852b15cb3dSCy Schubert */ 1862b15cb3dSCy Schubert mac_size = exten_len << 2; 1872b15cb3dSCy Schubert if (!auth_md5((char *)rpkt, pkt_len - mac_size, 1882b15cb3dSCy Schubert mac_size - 4, pkt_key)) { 1892b15cb3dSCy Schubert is_authentic = FALSE; 1902b15cb3dSCy Schubert break; 1912b15cb3dSCy Schubert } 1922b15cb3dSCy Schubert /* Yay! Things worked out! */ 1932b15cb3dSCy Schubert is_authentic = TRUE; 1942b15cb3dSCy Schubert TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n", 1952b15cb3dSCy Schubert func_name, stoa(sender), key_id)); 1962b15cb3dSCy Schubert break; 1972b15cb3dSCy Schubert 1982b15cb3dSCy Schubert default: 1992b15cb3dSCy Schubert msyslog(LOG_ERR, 2002b15cb3dSCy Schubert "%s: Unexpected extension length: %d. Discarding.", 2012b15cb3dSCy Schubert func_name, exten_len); 2022b15cb3dSCy Schubert return PACKET_UNUSEABLE; 2032b15cb3dSCy Schubert } 2042b15cb3dSCy Schubert 2052b15cb3dSCy Schubert switch (is_authentic) { 2062b15cb3dSCy Schubert 2072b15cb3dSCy Schubert case -1: /* unknown */ 2082b15cb3dSCy Schubert break; 2092b15cb3dSCy Schubert 2102b15cb3dSCy Schubert case 0: /* not authentic */ 2112b15cb3dSCy Schubert return SERVER_AUTH_FAIL; 2122b15cb3dSCy Schubert break; 2132b15cb3dSCy Schubert 2142b15cb3dSCy Schubert case 1: /* authentic */ 2152b15cb3dSCy Schubert break; 2162b15cb3dSCy Schubert 2172b15cb3dSCy Schubert default: /* error */ 2182b15cb3dSCy Schubert break; 2192b15cb3dSCy Schubert } 2202b15cb3dSCy Schubert 2212b15cb3dSCy Schubert /* Check for server's ntp version */ 2222b15cb3dSCy Schubert if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || 2232b15cb3dSCy Schubert PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { 2242b15cb3dSCy Schubert msyslog(LOG_ERR, 2252b15cb3dSCy Schubert "%s: Packet shows wrong version (%d)", 2262b15cb3dSCy Schubert func_name, PKT_VERSION(rpkt->li_vn_mode)); 2272b15cb3dSCy Schubert return SERVER_UNUSEABLE; 2282b15cb3dSCy Schubert } 2292b15cb3dSCy Schubert /* We want a server to sync with */ 2302b15cb3dSCy Schubert if (PKT_MODE(rpkt->li_vn_mode) != mode && 2312b15cb3dSCy Schubert PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) { 2322b15cb3dSCy Schubert msyslog(LOG_ERR, 2332b15cb3dSCy Schubert "%s: mode %d stratum %d", func_name, 2342b15cb3dSCy Schubert PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); 2352b15cb3dSCy Schubert return SERVER_UNUSEABLE; 2362b15cb3dSCy Schubert } 2372b15cb3dSCy Schubert /* Stratum is unspecified (0) check what's going on */ 2382b15cb3dSCy Schubert if (STRATUM_PKT_UNSPEC == rpkt->stratum) { 2392b15cb3dSCy Schubert char *ref_char; 2402b15cb3dSCy Schubert 2412b15cb3dSCy Schubert TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", 2422b15cb3dSCy Schubert func_name, rpkt->stratum)); 2432b15cb3dSCy Schubert ref_char = (char *) &rpkt->refid; 2442b15cb3dSCy Schubert TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name, 2452b15cb3dSCy Schubert ref_char[0], ref_char[1], ref_char[2], ref_char[3])); 2462b15cb3dSCy Schubert /* If it's a KOD packet we'll just use the KOD information */ 2472b15cb3dSCy Schubert if (ref_char[0] != 'X') { 2482b15cb3dSCy Schubert if (strncmp(ref_char, "DENY", 4) == 0) 2492b15cb3dSCy Schubert return KOD_DEMOBILIZE; 2502b15cb3dSCy Schubert if (strncmp(ref_char, "RSTR", 4) == 0) 2512b15cb3dSCy Schubert return KOD_DEMOBILIZE; 2522b15cb3dSCy Schubert if (strncmp(ref_char, "RATE", 4) == 0) 2532b15cb3dSCy Schubert return KOD_RATE; 2542b15cb3dSCy Schubert /* 2552b15cb3dSCy Schubert ** There are other interesting kiss codes which 2562b15cb3dSCy Schubert ** might be interesting for authentication. 2572b15cb3dSCy Schubert */ 2582b15cb3dSCy Schubert } 2592b15cb3dSCy Schubert } 2602b15cb3dSCy Schubert /* If the server is not synced it's not really useable for us */ 2612b15cb3dSCy Schubert if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) { 2622b15cb3dSCy Schubert msyslog(LOG_ERR, 2632b15cb3dSCy Schubert "%s: %s not in sync, skipping this server", 2642b15cb3dSCy Schubert func_name, stoa(sender)); 2652b15cb3dSCy Schubert return SERVER_UNUSEABLE; 2662b15cb3dSCy Schubert } 2672b15cb3dSCy Schubert 2682b15cb3dSCy Schubert /* 2692b15cb3dSCy Schubert * Decode the org timestamp and make sure we're getting a response 2702b15cb3dSCy Schubert * to our last request, but only if we're not in broadcast mode. 2712b15cb3dSCy Schubert */ 2722b15cb3dSCy Schubert if (MODE_BROADCAST == mode) 2732b15cb3dSCy Schubert return pkt_len; 2742b15cb3dSCy Schubert 2752b15cb3dSCy Schubert if (!L_ISEQU(&rpkt->org, &spkt->xmt)) { 2762b15cb3dSCy Schubert NTOHL_FP(&rpkt->org, &resp_org); 2772b15cb3dSCy Schubert NTOHL_FP(&spkt->xmt, &sent_xmt); 2782b15cb3dSCy Schubert msyslog(LOG_ERR, 2792b15cb3dSCy Schubert "%s response org expected to match sent xmt", 2802b15cb3dSCy Schubert stoa(sender)); 2812b15cb3dSCy Schubert msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org)); 2822b15cb3dSCy Schubert msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt)); 2832b15cb3dSCy Schubert return PACKET_UNUSEABLE; 2842b15cb3dSCy Schubert } 2852b15cb3dSCy Schubert 2862b15cb3dSCy Schubert return pkt_len; 2872b15cb3dSCy Schubert } 288