2 #include "networking.h"
19 printf("sntp sendpkt: Packet data:\n");
20 pkt_output(pkt, len, stdout);
23 TRACE(1, ("sntp sendpkt: Sending packet to %s ...\n",
26 cc = sendto(rsock, (void *)pkt, len, 0, &dest->sa,
28 if (cc == SOCKET_ERROR) {
29 msyslog(LOG_ERR, "Send to %s failed, %m",
33 TRACE(1, ("Packet sent.\n"));
39 /* Receive raw data */
48 GETSOCKNAME_SOCKLEN_TYPE slen;
51 slen = sizeof(*sender);
52 recvc = recvfrom(rsock, rdata, rdata_length, 0,
58 printf("Received %d bytes from %s:\n", recvc, sptoa(sender));
59 pkt_output((struct pkt *)rdata, recvc, stdout);
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
74 u_int32 *head, /* head of extension chain */
75 u_int32 *tail /* tail/end of extension chain */
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! */
91 ** Check if it's data for us and whether it's useable or not.
93 ** If not, return a failure code so we can delete this server from our list
94 ** and continue with another one.
103 const char * func_name
107 struct key * pkt_key;
112 u_int32 * packet_end;
118 is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;
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.
132 if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
134 "%s: Incredible packet length: %d. Discarding.",
136 return PACKET_UNUSEABLE;
138 /* Note: pkt_len must be a multiple of 4 at this point! */
139 packet_end = (u_int32*)((char*)rpkt + pkt_len);
140 exten_end = skip_efields(rpkt->exten, packet_end);
141 if (NULL == exten_end) {
143 "%s: Missing extension field. Discarding.",
145 return PACKET_UNUSEABLE;
147 /* get size of MAC in cells; can be zero */
148 exten_len = (u_int)(packet_end - exten_end);
150 /* deduce action required from remaining length */
153 case 0: /* no MAC at all */
156 case 1: /* crypto NAK */
157 key_id = ntohl(*exten_end);
158 printf("Crypto NAK = 0x%08x\n", key_id);
161 case 3: /* key ID + 3DES MAC -- unsupported! */
163 "%s: Key ID + 3DES MAC is unsupported. Discarding.",
165 return PACKET_UNUSEABLE;
167 case 5: /* key ID + MD5 MAC */
168 case 6: /* key ID + SHA MAC */
170 ** Look for the key used by the server in the specified
171 ** keyfile and if existent, fetch it or else leave the
174 key_id = ntohl(*exten_end);
175 get_key(key_id, &pkt_key);
177 printf("unrecognized key ID = 0x%08x\n", key_id);
181 ** Seems like we've got a key with matching keyid.
183 ** Generate a md5sum of the packet with the key from our
184 ** keyfile and compare those md5sums.
186 mac_size = exten_len << 2;
187 if (!auth_md5((char *)rpkt, pkt_len - mac_size,
188 mac_size - 4, pkt_key)) {
189 is_authentic = FALSE;
192 /* Yay! Things worked out! */
194 TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
195 func_name, stoa(sender), key_id));
200 "%s: Unexpected extension length: %d. Discarding.",
201 func_name, exten_len);
202 return PACKET_UNUSEABLE;
205 switch (is_authentic) {
207 case -1: /* unknown */
210 case 0: /* not authentic */
211 return SERVER_AUTH_FAIL;
214 case 1: /* authentic */
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) {
225 "%s: Packet shows wrong version (%d)",
226 func_name, PKT_VERSION(rpkt->li_vn_mode));
227 return SERVER_UNUSEABLE;
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) {
233 "%s: mode %d stratum %d", func_name,
234 PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
235 return SERVER_UNUSEABLE;
237 /* Stratum is unspecified (0) check what's going on */
238 if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
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)
255 ** There are other interesting kiss codes which
256 ** might be interesting for authentication.
260 /* If the server is not synced it's not really useable for us */
261 if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
263 "%s: %s not in sync, skipping this server",
264 func_name, stoa(sender));
265 return SERVER_UNUSEABLE;
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.
272 if (MODE_BROADCAST == mode)
275 if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
276 NTOHL_FP(&rpkt->org, &resp_org);
277 NTOHL_FP(&spkt->xmt, &sent_xmt);
279 "%s response org expected to match sent xmt",
281 msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
282 msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
283 return PACKET_UNUSEABLE;