1*2b15cb3dSCy Schubert #include <config.h> 2*2b15cb3dSCy Schubert #include "networking.h" 3*2b15cb3dSCy Schubert #include "ntp_debug.h" 4*2b15cb3dSCy Schubert 5*2b15cb3dSCy Schubert 6*2b15cb3dSCy Schubert /* Send a packet */ 7*2b15cb3dSCy Schubert int 8*2b15cb3dSCy Schubert sendpkt ( 9*2b15cb3dSCy Schubert SOCKET rsock, 10*2b15cb3dSCy Schubert sockaddr_u *dest, 11*2b15cb3dSCy Schubert struct pkt *pkt, 12*2b15cb3dSCy Schubert int len 13*2b15cb3dSCy Schubert ) 14*2b15cb3dSCy Schubert { 15*2b15cb3dSCy Schubert int cc; 16*2b15cb3dSCy Schubert 17*2b15cb3dSCy Schubert #ifdef DEBUG 18*2b15cb3dSCy Schubert if (debug > 2) { 19*2b15cb3dSCy Schubert printf("sntp sendpkt: Packet data:\n"); 20*2b15cb3dSCy Schubert pkt_output(pkt, len, stdout); 21*2b15cb3dSCy Schubert } 22*2b15cb3dSCy Schubert #endif 23*2b15cb3dSCy Schubert TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n", 24*2b15cb3dSCy Schubert sptoa(dest))); 25*2b15cb3dSCy Schubert 26*2b15cb3dSCy Schubert cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, 27*2b15cb3dSCy Schubert SOCKLEN(dest)); 28*2b15cb3dSCy Schubert if (cc == SOCKET_ERROR) { 29*2b15cb3dSCy Schubert msyslog(LOG_ERR, "Send to %s failed, %m", 30*2b15cb3dSCy Schubert sptoa(dest)); 31*2b15cb3dSCy Schubert return FALSE; 32*2b15cb3dSCy Schubert } 33*2b15cb3dSCy Schubert TRACE(1, ("Packet sent.\n")); 34*2b15cb3dSCy Schubert 35*2b15cb3dSCy Schubert return TRUE; 36*2b15cb3dSCy Schubert } 37*2b15cb3dSCy Schubert 38*2b15cb3dSCy Schubert 39*2b15cb3dSCy Schubert /* Receive raw data */ 40*2b15cb3dSCy Schubert int 41*2b15cb3dSCy Schubert recvdata( 42*2b15cb3dSCy Schubert SOCKET rsock, 43*2b15cb3dSCy Schubert sockaddr_u * sender, 44*2b15cb3dSCy Schubert void * rdata, 45*2b15cb3dSCy Schubert int rdata_length 46*2b15cb3dSCy Schubert ) 47*2b15cb3dSCy Schubert { 48*2b15cb3dSCy Schubert GETSOCKNAME_SOCKLEN_TYPE slen; 49*2b15cb3dSCy Schubert int recvc; 50*2b15cb3dSCy Schubert 51*2b15cb3dSCy Schubert slen = sizeof(*sender); 52*2b15cb3dSCy Schubert recvc = recvfrom(rsock, rdata, rdata_length, 0, 53*2b15cb3dSCy Schubert &sender->sa, &slen); 54*2b15cb3dSCy Schubert if (recvc < 0) 55*2b15cb3dSCy Schubert return recvc; 56*2b15cb3dSCy Schubert #ifdef DEBUG 57*2b15cb3dSCy Schubert if (debug > 2) { 58*2b15cb3dSCy Schubert printf("Received %d bytes from %s:\n", recvc, sptoa(sender)); 59*2b15cb3dSCy Schubert pkt_output((struct pkt *)rdata, recvc, stdout); 60*2b15cb3dSCy Schubert } 61*2b15cb3dSCy Schubert #endif 62*2b15cb3dSCy Schubert return recvc; 63*2b15cb3dSCy Schubert } 64*2b15cb3dSCy Schubert 65*2b15cb3dSCy Schubert /* Parsing from a short 'struct pkt' directly is bound to create 66*2b15cb3dSCy Schubert * coverity warnings. These are hard to avoid, as the formal declaration 67*2b15cb3dSCy Schubert * does not reflect the true layout in the presence of autokey extension 68*2b15cb3dSCy Schubert * fields. Parsing and skipping the extension fields of a received packet 69*2b15cb3dSCy Schubert * until there's only the MAC left is better done in this separate 70*2b15cb3dSCy Schubert * function. 71*2b15cb3dSCy Schubert */ 72*2b15cb3dSCy Schubert static void* 73*2b15cb3dSCy Schubert skip_efields( 74*2b15cb3dSCy Schubert u_int32 *head, /* head of extension chain */ 75*2b15cb3dSCy Schubert u_int32 *tail /* tail/end of extension chain */ 76*2b15cb3dSCy Schubert ) 77*2b15cb3dSCy Schubert { 78*2b15cb3dSCy Schubert 79*2b15cb3dSCy Schubert u_int nlen; /* next extension length */ 80*2b15cb3dSCy Schubert while ((tail - head) > 6) { 81*2b15cb3dSCy Schubert nlen = ntohl(*head++) & 0xffff; 82*2b15cb3dSCy Schubert nlen = (nlen + 3) >> 2; 83*2b15cb3dSCy Schubert if (nlen > (u_int)(tail - head) || nlen < 4) 84*2b15cb3dSCy Schubert return NULL; /* Blooper! Inconsistent! */ 85*2b15cb3dSCy Schubert head += nlen; 86*2b15cb3dSCy Schubert } 87*2b15cb3dSCy Schubert return head; 88*2b15cb3dSCy Schubert } 89*2b15cb3dSCy Schubert 90*2b15cb3dSCy Schubert /* 91*2b15cb3dSCy Schubert ** Check if it's data for us and whether it's useable or not. 92*2b15cb3dSCy Schubert ** 93*2b15cb3dSCy Schubert ** If not, return a failure code so we can delete this server from our list 94*2b15cb3dSCy Schubert ** and continue with another one. 95*2b15cb3dSCy Schubert */ 96*2b15cb3dSCy Schubert int 97*2b15cb3dSCy Schubert process_pkt ( 98*2b15cb3dSCy Schubert struct pkt *rpkt, 99*2b15cb3dSCy Schubert sockaddr_u *sender, 100*2b15cb3dSCy Schubert int pkt_len, 101*2b15cb3dSCy Schubert int mode, 102*2b15cb3dSCy Schubert struct pkt *spkt, 103*2b15cb3dSCy Schubert const char * func_name 104*2b15cb3dSCy Schubert ) 105*2b15cb3dSCy Schubert { 106*2b15cb3dSCy Schubert u_int key_id; 107*2b15cb3dSCy Schubert struct key * pkt_key; 108*2b15cb3dSCy Schubert int is_authentic; 109*2b15cb3dSCy Schubert int mac_size; 110*2b15cb3dSCy Schubert u_int exten_len; 111*2b15cb3dSCy Schubert u_int32 * exten_end; 112*2b15cb3dSCy Schubert u_int32 * packet_end; 113*2b15cb3dSCy Schubert l_fp sent_xmt; 114*2b15cb3dSCy Schubert l_fp resp_org; 115*2b15cb3dSCy Schubert 116*2b15cb3dSCy Schubert key_id = 0; 117*2b15cb3dSCy Schubert pkt_key = NULL; 118*2b15cb3dSCy Schubert is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1; 119*2b15cb3dSCy Schubert 120*2b15cb3dSCy Schubert /* 121*2b15cb3dSCy Schubert * Parse the extension field if present. We figure out whether 122*2b15cb3dSCy Schubert * an extension field is present by measuring the MAC size. If 123*2b15cb3dSCy Schubert * the number of words following the packet header is 0, no MAC 124*2b15cb3dSCy Schubert * is present and the packet is not authenticated. If 1, the 125*2b15cb3dSCy Schubert * packet is a crypto-NAK; if 3, the packet is authenticated 126*2b15cb3dSCy Schubert * with DES; if 5, the packet is authenticated with MD5; if 6, 127*2b15cb3dSCy Schubert * the packet is authenticated with SHA. If 2 or 4, the packet 128*2b15cb3dSCy Schubert * is a runt and discarded forthwith. If greater than 6, an 129*2b15cb3dSCy Schubert * extension field is present, so we subtract the length of the 130*2b15cb3dSCy Schubert * field and go around again. 131*2b15cb3dSCy Schubert */ 132*2b15cb3dSCy Schubert if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) { 133*2b15cb3dSCy Schubert msyslog(LOG_ERR, 134*2b15cb3dSCy Schubert "%s: Incredible packet length: %d. Discarding.", 135*2b15cb3dSCy Schubert func_name, pkt_len); 136*2b15cb3dSCy Schubert return PACKET_UNUSEABLE; 137*2b15cb3dSCy Schubert } 138*2b15cb3dSCy Schubert /* Note: pkt_len must be a multiple of 4 at this point! */ 139*2b15cb3dSCy Schubert packet_end = (u_int32*)((char*)rpkt + pkt_len); 140*2b15cb3dSCy Schubert exten_end = skip_efields(rpkt->exten, packet_end); 141*2b15cb3dSCy Schubert if (NULL == exten_end) { 142*2b15cb3dSCy Schubert msyslog(LOG_ERR, 143*2b15cb3dSCy Schubert "%s: Missing extension field. Discarding.", 144*2b15cb3dSCy Schubert func_name); 145*2b15cb3dSCy Schubert return PACKET_UNUSEABLE; 146*2b15cb3dSCy Schubert } 147*2b15cb3dSCy Schubert /* get size of MAC in cells; can be zero */ 148*2b15cb3dSCy Schubert exten_len = (u_int)(packet_end - exten_end); 149*2b15cb3dSCy Schubert 150*2b15cb3dSCy Schubert /* deduce action required from remaining length */ 151*2b15cb3dSCy Schubert switch (exten_len) { 152*2b15cb3dSCy Schubert 153*2b15cb3dSCy Schubert case 0: /* no MAC at all */ 154*2b15cb3dSCy Schubert break; 155*2b15cb3dSCy Schubert 156*2b15cb3dSCy Schubert case 1: /* crypto NAK */ 157*2b15cb3dSCy Schubert key_id = ntohl(*exten_end); 158*2b15cb3dSCy Schubert printf("Crypto NAK = 0x%08x\n", key_id); 159*2b15cb3dSCy Schubert break; 160*2b15cb3dSCy Schubert 161*2b15cb3dSCy Schubert case 3: /* key ID + 3DES MAC -- unsupported! */ 162*2b15cb3dSCy Schubert msyslog(LOG_ERR, 163*2b15cb3dSCy Schubert "%s: Key ID + 3DES MAC is unsupported. Discarding.", 164*2b15cb3dSCy Schubert func_name); 165*2b15cb3dSCy Schubert return PACKET_UNUSEABLE; 166*2b15cb3dSCy Schubert 167*2b15cb3dSCy Schubert case 5: /* key ID + MD5 MAC */ 168*2b15cb3dSCy Schubert case 6: /* key ID + SHA MAC */ 169*2b15cb3dSCy Schubert /* 170*2b15cb3dSCy Schubert ** Look for the key used by the server in the specified 171*2b15cb3dSCy Schubert ** keyfile and if existent, fetch it or else leave the 172*2b15cb3dSCy Schubert ** pointer untouched 173*2b15cb3dSCy Schubert */ 174*2b15cb3dSCy Schubert key_id = ntohl(*exten_end); 175*2b15cb3dSCy Schubert get_key(key_id, &pkt_key); 176*2b15cb3dSCy Schubert if (!pkt_key) { 177*2b15cb3dSCy Schubert printf("unrecognized key ID = 0x%08x\n", key_id); 178*2b15cb3dSCy Schubert break; 179*2b15cb3dSCy Schubert } 180*2b15cb3dSCy Schubert /* 181*2b15cb3dSCy Schubert ** Seems like we've got a key with matching keyid. 182*2b15cb3dSCy Schubert ** 183*2b15cb3dSCy Schubert ** Generate a md5sum of the packet with the key from our 184*2b15cb3dSCy Schubert ** keyfile and compare those md5sums. 185*2b15cb3dSCy Schubert */ 186*2b15cb3dSCy Schubert mac_size = exten_len << 2; 187*2b15cb3dSCy Schubert if (!auth_md5((char *)rpkt, pkt_len - mac_size, 188*2b15cb3dSCy Schubert mac_size - 4, pkt_key)) { 189*2b15cb3dSCy Schubert is_authentic = FALSE; 190*2b15cb3dSCy Schubert break; 191*2b15cb3dSCy Schubert } 192*2b15cb3dSCy Schubert /* Yay! Things worked out! */ 193*2b15cb3dSCy Schubert is_authentic = TRUE; 194*2b15cb3dSCy Schubert TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n", 195*2b15cb3dSCy Schubert func_name, stoa(sender), key_id)); 196*2b15cb3dSCy Schubert break; 197*2b15cb3dSCy Schubert 198*2b15cb3dSCy Schubert default: 199*2b15cb3dSCy Schubert msyslog(LOG_ERR, 200*2b15cb3dSCy Schubert "%s: Unexpected extension length: %d. Discarding.", 201*2b15cb3dSCy Schubert func_name, exten_len); 202*2b15cb3dSCy Schubert return PACKET_UNUSEABLE; 203*2b15cb3dSCy Schubert } 204*2b15cb3dSCy Schubert 205*2b15cb3dSCy Schubert switch (is_authentic) { 206*2b15cb3dSCy Schubert 207*2b15cb3dSCy Schubert case -1: /* unknown */ 208*2b15cb3dSCy Schubert break; 209*2b15cb3dSCy Schubert 210*2b15cb3dSCy Schubert case 0: /* not authentic */ 211*2b15cb3dSCy Schubert return SERVER_AUTH_FAIL; 212*2b15cb3dSCy Schubert break; 213*2b15cb3dSCy Schubert 214*2b15cb3dSCy Schubert case 1: /* authentic */ 215*2b15cb3dSCy Schubert break; 216*2b15cb3dSCy Schubert 217*2b15cb3dSCy Schubert default: /* error */ 218*2b15cb3dSCy Schubert break; 219*2b15cb3dSCy Schubert } 220*2b15cb3dSCy Schubert 221*2b15cb3dSCy Schubert /* Check for server's ntp version */ 222*2b15cb3dSCy Schubert if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || 223*2b15cb3dSCy Schubert PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { 224*2b15cb3dSCy Schubert msyslog(LOG_ERR, 225*2b15cb3dSCy Schubert "%s: Packet shows wrong version (%d)", 226*2b15cb3dSCy Schubert func_name, PKT_VERSION(rpkt->li_vn_mode)); 227*2b15cb3dSCy Schubert return SERVER_UNUSEABLE; 228*2b15cb3dSCy Schubert } 229*2b15cb3dSCy Schubert /* We want a server to sync with */ 230*2b15cb3dSCy Schubert if (PKT_MODE(rpkt->li_vn_mode) != mode && 231*2b15cb3dSCy Schubert PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) { 232*2b15cb3dSCy Schubert msyslog(LOG_ERR, 233*2b15cb3dSCy Schubert "%s: mode %d stratum %d", func_name, 234*2b15cb3dSCy Schubert PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); 235*2b15cb3dSCy Schubert return SERVER_UNUSEABLE; 236*2b15cb3dSCy Schubert } 237*2b15cb3dSCy Schubert /* Stratum is unspecified (0) check what's going on */ 238*2b15cb3dSCy Schubert if (STRATUM_PKT_UNSPEC == rpkt->stratum) { 239*2b15cb3dSCy Schubert char *ref_char; 240*2b15cb3dSCy Schubert 241*2b15cb3dSCy Schubert TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", 242*2b15cb3dSCy Schubert func_name, rpkt->stratum)); 243*2b15cb3dSCy Schubert ref_char = (char *) &rpkt->refid; 244*2b15cb3dSCy Schubert TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name, 245*2b15cb3dSCy Schubert ref_char[0], ref_char[1], ref_char[2], ref_char[3])); 246*2b15cb3dSCy Schubert /* If it's a KOD packet we'll just use the KOD information */ 247*2b15cb3dSCy Schubert if (ref_char[0] != 'X') { 248*2b15cb3dSCy Schubert if (strncmp(ref_char, "DENY", 4) == 0) 249*2b15cb3dSCy Schubert return KOD_DEMOBILIZE; 250*2b15cb3dSCy Schubert if (strncmp(ref_char, "RSTR", 4) == 0) 251*2b15cb3dSCy Schubert return KOD_DEMOBILIZE; 252*2b15cb3dSCy Schubert if (strncmp(ref_char, "RATE", 4) == 0) 253*2b15cb3dSCy Schubert return KOD_RATE; 254*2b15cb3dSCy Schubert /* 255*2b15cb3dSCy Schubert ** There are other interesting kiss codes which 256*2b15cb3dSCy Schubert ** might be interesting for authentication. 257*2b15cb3dSCy Schubert */ 258*2b15cb3dSCy Schubert } 259*2b15cb3dSCy Schubert } 260*2b15cb3dSCy Schubert /* If the server is not synced it's not really useable for us */ 261*2b15cb3dSCy Schubert if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) { 262*2b15cb3dSCy Schubert msyslog(LOG_ERR, 263*2b15cb3dSCy Schubert "%s: %s not in sync, skipping this server", 264*2b15cb3dSCy Schubert func_name, stoa(sender)); 265*2b15cb3dSCy Schubert return SERVER_UNUSEABLE; 266*2b15cb3dSCy Schubert } 267*2b15cb3dSCy Schubert 268*2b15cb3dSCy Schubert /* 269*2b15cb3dSCy Schubert * Decode the org timestamp and make sure we're getting a response 270*2b15cb3dSCy Schubert * to our last request, but only if we're not in broadcast mode. 271*2b15cb3dSCy Schubert */ 272*2b15cb3dSCy Schubert if (MODE_BROADCAST == mode) 273*2b15cb3dSCy Schubert return pkt_len; 274*2b15cb3dSCy Schubert 275*2b15cb3dSCy Schubert if (!L_ISEQU(&rpkt->org, &spkt->xmt)) { 276*2b15cb3dSCy Schubert NTOHL_FP(&rpkt->org, &resp_org); 277*2b15cb3dSCy Schubert NTOHL_FP(&spkt->xmt, &sent_xmt); 278*2b15cb3dSCy Schubert msyslog(LOG_ERR, 279*2b15cb3dSCy Schubert "%s response org expected to match sent xmt", 280*2b15cb3dSCy Schubert stoa(sender)); 281*2b15cb3dSCy Schubert msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org)); 282*2b15cb3dSCy Schubert msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt)); 283*2b15cb3dSCy Schubert return PACKET_UNUSEABLE; 284*2b15cb3dSCy Schubert } 285*2b15cb3dSCy Schubert 286*2b15cb3dSCy Schubert return pkt_len; 287*2b15cb3dSCy Schubert } 288