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