]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/towire.c
mDNSResponder-1096.60.2.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / towire.c
1 /* wire.c
2 *
3 * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * DNS wire-format functions.
18 *
19 * These are really simple functions for constructing DNS messages wire format.
20 * The flow is that there is a transaction structure which contains pointers to both
21 * a message output buffer and a response input buffer. The structure is initialized,
22 * and then the various wire format functions are called repeatedly to store data.
23 * If an error occurs during this process, it's okay to just keep going, because the
24 * error is recorded in the transaction; once all of the copy-in functions have been
25 * called, the error status can be checked once at the end.
26 */
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <sys/errno.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
34 #include "srp.h"
35 #include "dns-msg.h"
36 #include "srp-crypto.h"
37
38 #ifndef NO_CLOCK
39 #include <sys/time.h>
40 #endif
41
42 // Convert a name to wire format. Does not store the root label (0) at the end. Does not support binary labels.
43 void
44 dns_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
45 dns_towire_state_t *NONNULL txn,
46 const char *NONNULL name)
47 {
48 const char *next, *cur, *end;
49 dns_name_pointer_t np;
50 if (!txn->error) {
51 memset(&np, 0, sizeof np);
52 np.message_start = (u_int8_t *)txn->message;
53 np.name_start = txn->p;
54
55 cur = name;
56 do {
57 end = strchr(cur, '.');
58 if (end == NULL) {
59 end = cur + strlen(cur);
60 if (end == cur) {
61 break;
62 }
63 next = NULL;
64 } else {
65 if (end == cur) {
66 break;
67 }
68 next = end + 1;
69 }
70
71 // Is there no space?
72 if (txn->p + (1 + end - cur) >= txn->lim) {
73 txn->error = ENOBUFS;
74 return;
75 }
76
77 // Is the label too long?
78 if (end - cur > DNS_MAX_LABEL_SIZE) {
79 txn->error = ENAMETOOLONG;
80 return;
81 }
82
83 // Store the label length
84 *txn->p++ = (uint8_t)(end - cur);
85
86 // Store the label.
87 memcpy(txn->p, cur, end - cur);
88 txn->p += (end - cur);
89 np.num_labels++;
90 np.length += 1 + (end - cur);
91
92 cur = next;
93 } while (next != NULL);
94
95 if (np.length > DNS_MAX_NAME_SIZE) {
96 txn->error = ENAMETOOLONG;
97 return;
98 }
99 if (r_pointer != NULL) {
100 *r_pointer = np;
101 }
102 }
103 }
104
105 // Like dns_name_to_wire, but includes the root label at the end.
106 void
107 dns_full_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
108 dns_towire_state_t *NONNULL txn,
109 const char *NONNULL name)
110 {
111 dns_name_pointer_t np;
112 if (!txn->error) {
113 memset(&np, 0, sizeof np);
114 dns_name_to_wire(&np, txn, name);
115 if (!txn->error) {
116 if (txn->p + 1 >= txn->lim) {
117 txn->error = ENOBUFS;
118 return;
119 }
120 *txn->p++ = 0;
121 np.num_labels++;
122 np.length += 1;
123 if (np.length > DNS_MAX_NAME_SIZE) {
124 txn->error = ENAMETOOLONG;
125 return;
126 }
127 if (r_pointer) {
128 *r_pointer = np;
129 }
130 }
131 }
132 }
133
134 // Store a pointer to a name that's already in the message.
135 void
136 dns_pointer_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
137 dns_towire_state_t *NONNULL txn,
138 dns_name_pointer_t *NONNULL pointer)
139 {
140 if (!txn->error) {
141 u_int16_t offset = pointer->name_start - pointer->message_start;
142 if (offset > DNS_MAX_POINTER) {
143 txn->error = ETOOMANYREFS;
144 return;
145 }
146 if (txn->p + 2 >= txn->lim) {
147 txn->error = ENOBUFS;
148 return;
149 }
150 *txn->p++ = 0xc0 | (offset >> 8);
151 *txn->p++ = offset & 0xff;
152 if (r_pointer) {
153 r_pointer->num_labels += pointer->num_labels;
154 r_pointer->length += pointer->length + 1;
155 if (r_pointer->length > DNS_MAX_NAME_SIZE) {
156 txn->error = ENAMETOOLONG;
157 return;
158 }
159 }
160 }
161 }
162
163 void
164 dns_u8_to_wire(dns_towire_state_t *NONNULL txn,
165 uint8_t val)
166 {
167 if (!txn->error) {
168 if (txn->p + 1 >= txn->lim) {
169 txn->error = ENOBUFS;
170 return;
171 }
172 *txn->p++ = val;
173 }
174 }
175
176 // Store a 16-bit integer in network byte order
177 void
178 dns_u16_to_wire(dns_towire_state_t *NONNULL txn,
179 uint16_t val)
180 {
181 if (!txn->error) {
182 if (txn->p + 2 >= txn->lim) {
183 txn->error = ENOBUFS;
184 return;
185 }
186 *txn->p++ = val >> 8;
187 *txn->p++ = val & 0xff;
188 }
189 }
190
191 void
192 dns_u32_to_wire(dns_towire_state_t *NONNULL txn,
193 uint32_t val)
194 {
195 if (!txn->error) {
196 if (txn->p + 4 >= txn->lim) {
197 txn->error = ENOBUFS;
198 return;
199 }
200 *txn->p++ = val >> 24;
201 *txn->p++ = (val >> 16) & 0xff;
202 *txn->p++ = (val >> 8) & 0xff;
203 *txn->p++ = val & 0xff;
204 }
205 }
206
207 void
208 dns_ttl_to_wire(dns_towire_state_t *NONNULL txn,
209 int32_t val)
210 {
211 if (!txn->error) {
212 if (val < 0) {
213 txn->error = EINVAL;
214 return;
215 }
216 dns_u32_to_wire(txn, (uint32_t)val);
217 }
218 }
219
220 void
221 dns_rdlength_begin(dns_towire_state_t *NONNULL txn)
222 {
223 if (!txn->error) {
224 if (txn->p + 2 >= txn->lim) {
225 txn->error = ENOBUFS;
226 return;
227 }
228 if (txn->p_rdlength != NULL) {
229 txn->error = EINVAL;
230 return;
231 }
232 txn->p_rdlength = txn->p;
233 txn->p += 2;
234 }
235 }
236
237 void
238 dns_rdlength_end(dns_towire_state_t *NONNULL txn)
239 {
240 int rdlength;
241 if (!txn->error) {
242 if (txn->p_rdlength == NULL) {
243 txn->error = EINVAL;
244 return;
245 }
246 rdlength = txn->p - txn->p_rdlength - 2;
247 txn->p_rdlength[0] = rdlength >> 8;
248 txn->p_rdlength[1] = rdlength & 0xff;
249 txn->p_rdlength = NULL;
250 }
251 }
252
253 void
254 dns_rdata_a_to_wire(dns_towire_state_t *NONNULL txn,
255 const char *NONNULL ip_address)
256 {
257 if (!txn->error) {
258 if (txn->p + 4 >= txn->lim) {
259 txn->error = ENOBUFS;
260 return;
261 }
262 if (!inet_pton(AF_INET, ip_address, txn->p)) {
263 txn->error = EINVAL;
264 }
265 txn->p += 4;
266 }
267 }
268
269 void
270 dns_rdata_aaaa_to_wire(dns_towire_state_t *NONNULL txn,
271 const char *NONNULL ip_address)
272 {
273 if (!txn->error) {
274 if (txn->p + 16 >= txn->lim) {
275 txn->error = ENOBUFS;
276 return;
277 }
278 if (!inet_pton(AF_INET6, ip_address, txn->p)) {
279 txn->error = EINVAL;
280 }
281 txn->p += 16;
282 }
283 }
284
285 uint16_t
286 dns_rdata_key_to_wire(dns_towire_state_t *NONNULL txn,
287 unsigned key_type,
288 unsigned name_type,
289 unsigned signatory,
290 srp_key_t *key)
291 {
292 int key_len = srp_pubkey_length(key);
293 uint8_t *rdata = txn->p;
294 uint32_t key_tag;
295 int i, rdlen;
296
297 if (!txn->error) {
298 if (key_type > 3 || name_type > 3 || signatory > 15) {
299 txn->error = EINVAL;
300 return 0;
301 }
302 if (txn->p + key_len + 4 >= txn->lim) {
303 txn->error = ENOBUFS;
304 return 0;
305 }
306 *txn->p++ = (key_type << 6) | name_type;
307 *txn->p++ = signatory;
308 *txn->p++ = 3; // protocol type is always 3
309 *txn->p++ = srp_key_algorithm(key);
310 srp_pubkey_copy(txn->p, key_len, key);
311 txn->p += key_len;
312 }
313 rdlen = txn->p - rdata;
314
315 // Compute the key tag
316 key_tag = 0;
317 for (i = 0; i < rdlen; i++) {
318 key_tag += (i & 1) ? rdata[i] : rdata[i] << 8;
319 }
320 key_tag += (key_tag >> 16) & 0xFFFF;
321 return (uint16_t)(key_tag & 0xFFFF);
322 }
323
324 void
325 dns_rdata_txt_to_wire(dns_towire_state_t *NONNULL txn,
326 const char *NONNULL txt_record)
327 {
328 if (!txn->error) {
329 unsigned len = strlen(txt_record);
330 if (txn->p + len + 1 >= txn->lim) {
331 txn->error = ENOBUFS;
332 return;
333 }
334 if (len > 255) {
335 txn->error = ENAMETOOLONG;
336 return;
337 }
338 *txn->p++ = (u_int8_t)len;
339 memcpy(txn->p, txt_record, len);
340 txn->p += len;
341 }
342 }
343
344 void
345 dns_rdata_raw_data_to_wire(dns_towire_state_t *NONNULL txn, const void *NONNULL raw_data, size_t length)
346 {
347 if (!txn->error) {
348 if (txn->p + length >= txn->lim) {
349 txn->error = ENOBUFS;
350 return;
351 }
352 memcpy(txn->p, raw_data, length);
353 txn->p += length;
354 }
355 }
356
357 void
358 dns_edns0_header_to_wire(dns_towire_state_t *NONNULL txn,
359 int mtu,
360 int xrcode,
361 int version,
362 int DO)
363 {
364 if (!txn->error) {
365 if (txn->p + 9 >= txn->lim) {
366 txn->error = ENOBUFS;
367 return;
368 }
369 *txn->p++ = 0; // root label
370 dns_u16_to_wire(txn, dns_rrtype_opt);
371 dns_u16_to_wire(txn, mtu);
372 *txn->p++ = xrcode;
373 *txn->p++ = version;
374 *txn->p++ = DO << 7; // flags (usb)
375 *txn->p++ = 0; // flags (lsb, mbz)
376 }
377 }
378
379 void
380 dns_edns0_option_begin(dns_towire_state_t *NONNULL txn)
381 {
382 if (!txn->error) {
383 if (txn->p + 2 >= txn->lim) {
384 txn->error = ENOBUFS;
385 return;
386 }
387 if (txn->p_opt != NULL) {
388 txn->error = EINVAL;
389 return;
390 }
391 txn->p_opt = txn->p;
392 txn->p += 2;
393 }
394 }
395
396 void
397 dns_edns0_option_end(dns_towire_state_t *NONNULL txn)
398 {
399 int opt_length;
400 if (!txn->error) {
401 if (txn->p_opt == NULL) {
402 txn->error = EINVAL;
403 return;
404 }
405 opt_length = txn->p - txn->p_opt - 2;
406 txn->p_opt[0] = opt_length >> 8;
407 txn->p_opt[1] = opt_length & 0xff;
408 txn->p_opt = NULL;
409 }
410 }
411
412 void
413 dns_sig0_signature_to_wire(dns_towire_state_t *NONNULL txn,
414 srp_key_t *key,
415 uint16_t key_tag,
416 dns_name_pointer_t *NONNULL signer,
417 const char *NONNULL signer_fqdn)
418 {
419 int siglen = srp_signature_length(key);
420 uint8_t *start, *p_signer, *p_signature, *rrstart = txn->p;
421 #ifndef NO_CLOCK
422 struct timeval now;
423 #endif
424
425 // 1 name (root)
426 // 2 type (SIG)
427 // 2 class (0)
428 // 4 TTL (0)
429 // 18 SIG RDATA up to signer name
430 // 2 signer name (always a pointer)
431 // 29 bytes so far
432 // signature data (depends on algorithm, e.g. 64 for ECDSASHA256)
433 // so e.g. 93 bytes total
434
435 if (!txn->error) {
436 dns_u8_to_wire(txn, 0); // root label
437 dns_u16_to_wire(txn, dns_rrtype_sig);
438 dns_u16_to_wire(txn, 0); // class
439 dns_ttl_to_wire(txn, 0); // SIG RR TTL
440 dns_rdlength_begin(txn);
441 start = txn->p;
442 dns_u16_to_wire(txn, 0); // type = 0 for transaction signature
443 dns_u8_to_wire(txn, srp_key_algorithm(key));
444 dns_u8_to_wire(txn, 0); // labels field doesn't apply for transaction signature
445 dns_ttl_to_wire(txn, 0); // original ttl doesn't apply
446 #ifdef NO_CLOCK
447 dns_u32_to_wire(txn, 0); // Indicate that we have no clock: set expiry and inception times to zero
448 dns_u32_to_wire(txn, 0);
449 #else
450 gettimeofday(&now, NULL);
451 dns_u32_to_wire(txn, now.tv_sec + 300); // signature expiration time is five minutes from now
452 dns_u32_to_wire(txn, now.tv_sec - 300); // signature inception time, five minutes in the past
453 #endif
454 dns_u16_to_wire(txn, key_tag);
455 p_signer = txn->p;
456 // We store the name in uncompressed form because that's what we have to sign
457 dns_full_name_to_wire(NULL, txn, signer_fqdn);
458 // And that means we're going to have to copy the signature back earlier in the packet.
459 p_signature = txn->p;
460
461 // Sign the message, signature RRDATA (less signature) first.
462 srp_sign(txn->p, siglen, (uint8_t *)txn->message, rrstart - (uint8_t *)txn->message,
463 start, txn->p - start, key);
464
465 // Now that it's signed, back up and store the pointer to the name, because we're trying
466 // to be as compact as possible.
467 txn->p = p_signer;
468 dns_pointer_to_wire(NULL, txn, signer); // Pointer to the owner name the key is attached to
469 // And move the signature earlier in the packet.
470 memmove(txn->p, p_signature, siglen);
471
472 txn->p += siglen;
473 dns_rdlength_end(txn);
474 }
475 }
476
477 int
478 dns_send_to_server(dns_transaction_t *NONNULL txn,
479 const char *NONNULL anycast_address, uint16_t port,
480 dns_response_callback_t NONNULL callback)
481 {
482 union {
483 struct sockaddr_storage s;
484 struct sockaddr sa;
485 struct sockaddr_in sin;
486 struct sockaddr_in6 sin6;
487 } addr, from;
488 socklen_t len, fromlen;
489 ssize_t rv, datasize;
490
491 if (!txn->towire.error) {
492 memset(&addr, 0, sizeof addr);
493
494 // Try IPv4 first because IPv6 addresses are never valid IPv4 addresses
495 if (inet_pton(AF_INET, anycast_address, &addr.sin.sin_addr)) {
496 addr.sin.sin_family = AF_INET;
497 addr.sin.sin_port = htons(port);
498 len = sizeof addr.sin;
499 } else if (inet_pton(AF_INET6, anycast_address, &addr.sin6.sin6_addr)) {
500 addr.sin6.sin6_family = AF_INET6;
501 addr.sin6.sin6_port = htons(port);
502 len = sizeof addr.sin6;
503 } else {
504 txn->towire.error = EPROTONOSUPPORT;
505 return -1;
506 }
507 //#ifdef HAVE_SA_LEN
508 addr.sa.sa_len = len;
509 //#endif
510
511 txn->sock = socket(addr.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
512 if (txn->sock < 0) {
513 txn->towire.error = errno;
514 return -1;
515 }
516
517 #if 0
518 memset(&myaddr, 0, sizeof myaddr);
519 myaddr.sin.sin_port = htons(9999);
520 myaddr.sa.sa_len = len;
521 myaddr.sa.sa_family = addr.sa.sa_family;
522 rv = bind(txn->sock, &myaddr.sa, len);
523 if (rv < 0) {
524 txn->towire.error = errno;
525 return -1;
526 }
527 #endif
528
529 datasize = txn->towire.p - ((u_int8_t *)txn->towire.message);
530 rv = sendto(txn->sock, txn->towire.message, datasize, 0, &addr.sa, len);
531 if (rv < 0) {
532 txn->towire.error = errno;
533 goto out;
534 }
535 if (rv != datasize) {
536 txn->towire.error = EMSGSIZE;
537 goto out;
538 }
539 fromlen = sizeof from;
540 rv = recvfrom(txn->sock, txn->response, sizeof *txn->response, 0, &from.sa, &fromlen);
541 if (rv < 0) {
542 txn->towire.error = errno;
543 goto out;
544 }
545 txn->response_length = rv;
546 }
547 out:
548 close(txn->sock);
549 txn->sock = 0;
550
551 if (txn->towire.error) {
552 return -1;
553 }
554 return 0;
555 }
556
557 // Local Variables:
558 // mode: C
559 // tab-width: 4
560 // c-file-style: "bsd"
561 // c-basic-offset: 4
562 // fill-column: 108
563 // indent-tabs-mode: nil
564 // End: