networking.c revision 294569
1183550Szec#include <config.h> 2196019Srwatson#include "networking.h" 3196019Srwatson#include "ntp_debug.h" 4196019Srwatson 5196019Srwatson 6196019Srwatson/* Send a packet */ 7196019Srwatsonint 8196019Srwatsonsendpkt ( 9196019Srwatson SOCKET rsock, 10195699Srwatson sockaddr_u *dest, 11195699Srwatson struct pkt *pkt, 12195705Srwatson int len 13183550Szec ) 14183550Szec{ 15183550Szec int cc; 16183550Szec 17183550Szec#ifdef DEBUG 18183550Szec if (debug > 2) { 19183550Szec printf("sntp sendpkt: Packet data:\n"); 20183550Szec pkt_output(pkt, len, stdout); 21183550Szec } 22195705Srwatson#endif 23183550Szec TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n", 24183550Szec sptoa(dest))); 25183550Szec 26183550Szec cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa, 27183550Szec SOCKLEN(dest)); 28183550Szec if (cc == SOCKET_ERROR) { 29183550Szec msyslog(LOG_ERR, "Send to %s failed, %m", 30183550Szec sptoa(dest)); 31183550Szec return FALSE; 32183550Szec } 33183550Szec TRACE(1, ("Packet sent.\n")); 34183550Szec 35183550Szec return TRUE; 36183550Szec} 37183550Szec 38195972Srwatson 39195972Srwatson/* Receive raw data */ 40195972Srwatsonint 41195972Srwatsonrecvdata( 42196019Srwatson SOCKET rsock, 43196019Srwatson sockaddr_u * sender, 44196019Srwatson void * rdata, 45195972Srwatson int rdata_length 46195972Srwatson ) 47195972Srwatson{ 48195972Srwatson GETSOCKNAME_SOCKLEN_TYPE slen; 49195972Srwatson int recvc; 50195972Srwatson 51195972Srwatson slen = sizeof(*sender); 52195972Srwatson recvc = recvfrom(rsock, rdata, rdata_length, 0, 53195972Srwatson &sender->sa, &slen); 54195972Srwatson if (recvc < 0) 55195699Srwatson return recvc; 56195699Srwatson#ifdef DEBUG 57183550Szec if (debug > 2) { 58192669Szec printf("Received %d bytes from %s:\n", recvc, sptoa(sender)); 59183550Szec pkt_output((struct pkt *)rdata, recvc, stdout); 60195972Srwatson } 61196019Srwatson#endif 62196019Srwatson return recvc; 63196019Srwatson} 64195972Srwatson 65195778Srwatson/* Parsing from a short 'struct pkt' directly is bound to create 66196019Srwatson * coverity warnings. These are hard to avoid, as the formal declaration 67196019Srwatson * does not reflect the true layout in the presence of autokey extension 68196019Srwatson * fields. Parsing and skipping the extension fields of a received packet 69196019Srwatson * until there's only the MAC left is better done in this separate 70196019Srwatson * function. 71196019Srwatson */ 72196019Srwatsonstatic void* 73196019Srwatsonskip_efields( 74196019Srwatson u_int32 *head, /* head of extension chain */ 75196019Srwatson u_int32 *tail /* tail/end of extension chain */ 76196019Srwatson ) 77196019Srwatson{ 78196019Srwatson 79196019Srwatson u_int nlen; /* next extension length */ 80196019Srwatson while ((tail - head) > 6) { 81196019Srwatson nlen = ntohl(*head++) & 0xffff; 82195778Srwatson nlen = (nlen + 3) >> 2; 83195778Srwatson if (nlen > (u_int)(tail - head) || nlen < 4) 84195778Srwatson return NULL; /* Blooper! Inconsistent! */ 85195778Srwatson head += nlen; 86195699Srwatson } 87196019Srwatson return head; 88253082Sae} 89253082Sae 90253082Sae/* 91253082Sae** Check if it's data for us and whether it's useable or not. 92253082Sae** 93253082Sae** If not, return a failure code so we can delete this server from our list 94253082Sae** and continue with another one. 95253082Sae*/ 96253082Saeint 97253082Saeprocess_pkt ( 98253082Sae struct pkt *rpkt, 99253082Sae sockaddr_u *sender, 100253082Sae int pkt_len, 101253082Sae int mode, 102253082Sae struct pkt *spkt, 103253082Sae const char * func_name 104253082Sae ) 105253082Sae{ 106253082Sae u_int key_id; 107253082Sae struct key * pkt_key; 108253082Sae int is_authentic; 109253082Sae int mac_size; 110253082Sae u_int exten_len; 111253082Sae u_int32 * exten_end; 112253082Sae u_int32 * packet_end; 113253082Sae l_fp sent_xmt; 114253082Sae l_fp resp_org; 115253082Sae 116253082Sae // key_id = 0; 117253082Sae pkt_key = NULL; 118253082Sae is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1; 119253082Sae 120253082Sae /* 121253082Sae * Parse the extension field if present. We figure out whether 122253082Sae * an extension field is present by measuring the MAC size. If 123253082Sae * the number of words following the packet header is 0, no MAC 124253082Sae * is present and the packet is not authenticated. If 1, the 125253082Sae * packet is a crypto-NAK; if 3, the packet is authenticated 126253082Sae * with DES; if 5, the packet is authenticated with MD5; if 6, 127253100Sae * the packet is authenticated with SHA. If 2 or 4, the packet 128253100Sae * is a runt and discarded forthwith. If greater than 6, an 129253082Sae * extension field is present, so we subtract the length of the 130253082Sae * field and go around again. 131253082Sae */ 132253082Sae if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) { 133253082Sae msyslog(LOG_ERR, 134253082Sae "%s: Incredible packet length: %d. Discarding.", 135253082Sae func_name, pkt_len); 136253082Sae return PACKET_UNUSEABLE; 137253082Sae } 138195699Srwatson /* Note: pkt_len must be a multiple of 4 at this point! */ 139196019Srwatson packet_end = (void*)((char*)rpkt + pkt_len); 140196019Srwatson exten_end = skip_efields(rpkt->exten, packet_end); 141196019Srwatson if (NULL == exten_end) { 142196019Srwatson msyslog(LOG_ERR, 143183550Szec "%s: Missing extension field. Discarding.", 144196019Srwatson func_name); 145206639Sjulian return PACKET_UNUSEABLE; 146206639Sjulian } 147206639Sjulian /* get size of MAC in cells; can be zero */ 148215701Sdim exten_len = (u_int)(packet_end - exten_end); 149206639Sjulian 150215701Sdim /* deduce action required from remaining length */ 151206639Sjulian switch (exten_len) { 152206639Sjulian 153206639Sjulian case 0: /* no MAC at all */ 154206639Sjulian break; 155206639Sjulian 156196019Srwatson case 1: /* crypto NAK */ 157196019Srwatson key_id = ntohl(*exten_end); 158196019Srwatson printf("Crypto NAK = 0x%08x\n", key_id); 159196019Srwatson break; 160196019Srwatson 161196019Srwatson case 3: /* key ID + 3DES MAC -- unsupported! */ 162196019Srwatson msyslog(LOG_ERR, 163196019Srwatson "%s: Key ID + 3DES MAC is unsupported. Discarding.", 164196019Srwatson func_name); 165196019Srwatson return PACKET_UNUSEABLE; 166196019Srwatson 167196019Srwatson case 5: /* key ID + MD5 MAC */ 168196019Srwatson case 6: /* key ID + SHA MAC */ 169196019Srwatson /* 170196019Srwatson ** Look for the key used by the server in the specified 171218559Sbz ** keyfile and if existent, fetch it or else leave the 172218559Sbz ** pointer untouched 173218559Sbz */ 174218559Sbz key_id = ntohl(*exten_end); 175218559Sbz get_key(key_id, &pkt_key); 176218559Sbz if (!pkt_key) { 177218559Sbz printf("unrecognized key ID = 0x%08x\n", key_id); 178218559Sbz break; 179218559Sbz } 180218559Sbz /* 181196019Srwatson ** Seems like we've got a key with matching keyid. 182203483Szec ** 183203483Szec ** Generate a md5sum of the packet with the key from our 184196019Srwatson ** keyfile and compare those md5sums. 185218559Sbz */ 186218559Sbz mac_size = exten_len << 2; 187218559Sbz if (!auth_md5(rpkt, pkt_len - mac_size, 188196019Srwatson mac_size - 4, pkt_key)) { 189196019Srwatson is_authentic = FALSE; 190196019Srwatson break; 191218555Sbz } 192196019Srwatson /* Yay! Things worked out! */ 193196019Srwatson is_authentic = TRUE; 194196019Srwatson TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n", 195196019Srwatson func_name, stoa(sender), key_id)); 196203483Szec break; 197196019Srwatson 198196019Srwatson default: 199196019Srwatson msyslog(LOG_ERR, 200196019Srwatson "%s: Unexpected extension length: %d. Discarding.", 201218559Sbz func_name, exten_len); 202218559Sbz return PACKET_UNUSEABLE; 203218559Sbz } 204218559Sbz 205196019Srwatson switch (is_authentic) { 206196019Srwatson 207196019Srwatson case -1: /* unknown */ 208196019Srwatson break; 209218567Sbz 210218567Sbz case 0: /* not authentic */ 211218567Sbz return SERVER_AUTH_FAIL; 212218567Sbz break; 213196019Srwatson 214196019Srwatson case 1: /* authentic */ 215196019Srwatson break; 216218567Sbz 217218567Sbz default: /* error */ 218218567Sbz break; 219218567Sbz } 220196019Srwatson 221196019Srwatson /* Check for server's ntp version */ 222218567Sbz if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || 223218567Sbz PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { 224218567Sbz msyslog(LOG_ERR, 225218567Sbz "%s: Packet shows wrong version (%d)", 226196019Srwatson func_name, PKT_VERSION(rpkt->li_vn_mode)); 227196019Srwatson return SERVER_UNUSEABLE; 228196019Srwatson } 229196019Srwatson /* We want a server to sync with */ 230196019Srwatson if (PKT_MODE(rpkt->li_vn_mode) != mode && 231196019Srwatson PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) { 232196019Srwatson msyslog(LOG_ERR, 233196019Srwatson "%s: mode %d stratum %d", func_name, 234196019Srwatson PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); 235196019Srwatson return SERVER_UNUSEABLE; 236196019Srwatson } 237196019Srwatson /* Stratum is unspecified (0) check what's going on */ 238196019Srwatson if (STRATUM_PKT_UNSPEC == rpkt->stratum) { 239196019Srwatson char *ref_char; 240196019Srwatson 241196019Srwatson TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", 242196019Srwatson func_name, rpkt->stratum)); 243196019Srwatson ref_char = (char *) &rpkt->refid; 244196019Srwatson TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name, 245196019Srwatson ref_char[0], ref_char[1], ref_char[2], ref_char[3])); 246196019Srwatson /* If it's a KOD packet we'll just use the KOD information */ 247196019Srwatson if (ref_char[0] != 'X') { 248196019Srwatson if (strncmp(ref_char, "DENY", 4) == 0) 249196019Srwatson return KOD_DEMOBILIZE; 250196019Srwatson if (strncmp(ref_char, "RSTR", 4) == 0) 251196019Srwatson return KOD_DEMOBILIZE; 252196019Srwatson if (strncmp(ref_char, "RATE", 4) == 0) 253196019Srwatson return KOD_RATE; 254196019Srwatson /* 255196019Srwatson ** There are other interesting kiss codes which 256196019Srwatson ** might be interesting for authentication. 257196019Srwatson */ 258196019Srwatson } 259196019Srwatson } 260196019Srwatson /* If the server is not synced it's not really useable for us */ 261195699Srwatson if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) { 262195699Srwatson msyslog(LOG_ERR, 263215701Sdim "%s: %s not in sync, skipping this server", 264215701Sdim func_name, stoa(sender)); 265215701Sdim return SERVER_UNUSEABLE; 266183550Szec } 267195727Srwatson 268183550Szec /* 269195699Srwatson * Decode the org timestamp and make sure we're getting a response 270195699Srwatson * to our last request, but only if we're not in broadcast mode. 271195699Srwatson */ 272195699Srwatson if (MODE_BROADCAST == mode) 273195727Srwatson return pkt_len; 274183550Szec 275195699Srwatson if (!L_ISEQU(&rpkt->org, &spkt->xmt)) { 276195727Srwatson NTOHL_FP(&rpkt->org, &resp_org); 277183550Szec NTOHL_FP(&spkt->xmt, &sent_xmt); 278195699Srwatson msyslog(LOG_ERR, 279195972Srwatson "%s response org expected to match sent xmt", 280195972Srwatson stoa(sender)); 281195972Srwatson msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org)); 282195972Srwatson msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt)); 283195972Srwatson return PACKET_UNUSEABLE; 284195972Srwatson } 285195972Srwatson 286195699Srwatson return pkt_len; 287195699Srwatson} 288195699Srwatson