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