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