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