1 /* $NetBSD: networking.c,v 1.13 2016/01/08 21:35:40 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 /* Note: pkt_len must be a multiple of 4 at this point! */ 141 packet_end = (void*)((char*)rpkt + pkt_len); 142 exten_end = skip_efields(rpkt->exten, packet_end); 143 if (NULL == exten_end) { 144 msyslog(LOG_ERR, 145 "%s: Missing extension field. Discarding.", 146 func_name); 147 return PACKET_UNUSEABLE; 148 } 149 /* get size of MAC in cells; can be zero */ 150 exten_len = (u_int)(packet_end - exten_end); 151 152 /* deduce action required from remaining length */ 153 switch (exten_len) { 154 155 case 0: /* no MAC at all */ 156 break; 157 158 case 1: /* crypto NAK */ 159 key_id = ntohl(*exten_end); 160 printf("Crypto NAK = 0x%08x\n", key_id); 161 break; 162 163 case 3: /* key ID + 3DES MAC -- unsupported! */ 164 msyslog(LOG_ERR, 165 "%s: Key ID + 3DES MAC is unsupported. Discarding.", 166 func_name); 167 return PACKET_UNUSEABLE; 168 169 case 5: /* key ID + MD5 MAC */ 170 case 6: /* key ID + SHA MAC */ 171 /* 172 ** Look for the key used by the server in the specified 173 ** keyfile and if existent, fetch it or else leave the 174 ** pointer untouched 175 */ 176 key_id = ntohl(*exten_end); 177 get_key(key_id, &pkt_key); 178 if (!pkt_key) { 179 printf("unrecognized key ID = 0x%08x\n", key_id); 180 break; 181 } 182 /* 183 ** Seems like we've got a key with matching keyid. 184 ** 185 ** Generate a md5sum of the packet with the key from our 186 ** keyfile and compare those md5sums. 187 */ 188 mac_size = exten_len << 2; 189 if (!auth_md5((char *)rpkt, pkt_len - mac_size, 190 mac_size - 4, pkt_key)) { 191 is_authentic = FALSE; 192 break; 193 } 194 /* Yay! Things worked out! */ 195 is_authentic = TRUE; 196 TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n", 197 func_name, stoa(sender), key_id)); 198 break; 199 200 default: 201 msyslog(LOG_ERR, 202 "%s: Unexpected extension length: %d. Discarding.", 203 func_name, exten_len); 204 return PACKET_UNUSEABLE; 205 } 206 207 switch (is_authentic) { 208 209 case -1: /* unknown */ 210 break; 211 212 case 0: /* not authentic */ 213 return SERVER_AUTH_FAIL; 214 break; 215 216 case 1: /* authentic */ 217 break; 218 219 default: /* error */ 220 break; 221 } 222 223 /* Check for server's ntp version */ 224 if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || 225 PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { 226 msyslog(LOG_ERR, 227 "%s: Packet shows wrong version (%d)", 228 func_name, PKT_VERSION(rpkt->li_vn_mode)); 229 return SERVER_UNUSEABLE; 230 } 231 /* We want a server to sync with */ 232 if (PKT_MODE(rpkt->li_vn_mode) != mode && 233 PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) { 234 msyslog(LOG_ERR, 235 "%s: mode %d stratum %d", func_name, 236 PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); 237 return SERVER_UNUSEABLE; 238 } 239 /* Stratum is unspecified (0) check what's going on */ 240 if (STRATUM_PKT_UNSPEC == rpkt->stratum) { 241 char *ref_char; 242 243 TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", 244 func_name, rpkt->stratum)); 245 ref_char = (char *) &rpkt->refid; 246 TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name, 247 ref_char[0], ref_char[1], ref_char[2], ref_char[3])); 248 /* If it's a KOD packet we'll just use the KOD information */ 249 if (ref_char[0] != 'X') { 250 if (strncmp(ref_char, "DENY", 4) == 0) 251 return KOD_DEMOBILIZE; 252 if (strncmp(ref_char, "RSTR", 4) == 0) 253 return KOD_DEMOBILIZE; 254 if (strncmp(ref_char, "RATE", 4) == 0) 255 return KOD_RATE; 256 /* 257 ** There are other interesting kiss codes which 258 ** might be interesting for authentication. 259 */ 260 } 261 } 262 /* If the server is not synced it's not really useable for us */ 263 if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) { 264 msyslog(LOG_ERR, 265 "%s: %s not in sync, skipping this server", 266 func_name, stoa(sender)); 267 return SERVER_UNUSEABLE; 268 } 269 270 /* 271 * Decode the org timestamp and make sure we're getting a response 272 * to our last request, but only if we're not in broadcast mode. 273 */ 274 if (MODE_BROADCAST == mode) 275 return pkt_len; 276 277 if (!L_ISEQU(&rpkt->org, &spkt->xmt)) { 278 NTOHL_FP(&rpkt->org, &resp_org); 279 NTOHL_FP(&spkt->xmt, &sent_xmt); 280 msyslog(LOG_ERR, 281 "%s response org expected to match sent xmt", 282 stoa(sender)); 283 msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org)); 284 msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt)); 285 return PACKET_UNUSEABLE; 286 } 287 288 return pkt_len; 289 } 290