3 * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * DNS wire-format functions.
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.
31 #include <sys/errno.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
36 #include "srp-crypto.h"
42 // Convert a name to wire format. Does not store the root label (0) at the end. Does not support binary labels.
44 dns_name_to_wire(dns_name_pointer_t
*NULLABLE r_pointer
,
45 dns_towire_state_t
*NONNULL txn
,
46 const char *NONNULL name
)
48 const char *next
, *cur
, *end
;
49 dns_name_pointer_t np
;
51 memset(&np
, 0, sizeof np
);
52 np
.message_start
= (u_int8_t
*)txn
->message
;
53 np
.name_start
= txn
->p
;
57 end
= strchr(cur
, '.');
59 end
= cur
+ strlen(cur
);
72 if (txn
->p
+ (1 + end
- cur
) >= txn
->lim
) {
77 // Is the label too long?
78 if (end
- cur
> DNS_MAX_LABEL_SIZE
) {
79 txn
->error
= ENAMETOOLONG
;
83 // Store the label length
84 *txn
->p
++ = (uint8_t)(end
- cur
);
87 memcpy(txn
->p
, cur
, end
- cur
);
88 txn
->p
+= (end
- cur
);
90 np
.length
+= 1 + (end
- cur
);
93 } while (next
!= NULL
);
95 if (np
.length
> DNS_MAX_NAME_SIZE
) {
96 txn
->error
= ENAMETOOLONG
;
99 if (r_pointer
!= NULL
) {
105 // Like dns_name_to_wire, but includes the root label at the end.
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
)
111 dns_name_pointer_t np
;
113 memset(&np
, 0, sizeof np
);
114 dns_name_to_wire(&np
, txn
, name
);
116 if (txn
->p
+ 1 >= txn
->lim
) {
117 txn
->error
= ENOBUFS
;
123 if (np
.length
> DNS_MAX_NAME_SIZE
) {
124 txn
->error
= ENAMETOOLONG
;
134 // Store a pointer to a name that's already in the message.
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
)
141 u_int16_t offset
= pointer
->name_start
- pointer
->message_start
;
142 if (offset
> DNS_MAX_POINTER
) {
143 txn
->error
= ETOOMANYREFS
;
146 if (txn
->p
+ 2 >= txn
->lim
) {
147 txn
->error
= ENOBUFS
;
150 *txn
->p
++ = 0xc0 | (offset
>> 8);
151 *txn
->p
++ = offset
& 0xff;
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
;
164 dns_u8_to_wire(dns_towire_state_t
*NONNULL txn
,
168 if (txn
->p
+ 1 >= txn
->lim
) {
169 txn
->error
= ENOBUFS
;
176 // Store a 16-bit integer in network byte order
178 dns_u16_to_wire(dns_towire_state_t
*NONNULL txn
,
182 if (txn
->p
+ 2 >= txn
->lim
) {
183 txn
->error
= ENOBUFS
;
186 *txn
->p
++ = val
>> 8;
187 *txn
->p
++ = val
& 0xff;
192 dns_u32_to_wire(dns_towire_state_t
*NONNULL txn
,
196 if (txn
->p
+ 4 >= txn
->lim
) {
197 txn
->error
= ENOBUFS
;
200 *txn
->p
++ = val
>> 24;
201 *txn
->p
++ = (val
>> 16) & 0xff;
202 *txn
->p
++ = (val
>> 8) & 0xff;
203 *txn
->p
++ = val
& 0xff;
208 dns_ttl_to_wire(dns_towire_state_t
*NONNULL txn
,
216 dns_u32_to_wire(txn
, (uint32_t)val
);
221 dns_rdlength_begin(dns_towire_state_t
*NONNULL txn
)
224 if (txn
->p
+ 2 >= txn
->lim
) {
225 txn
->error
= ENOBUFS
;
228 if (txn
->p_rdlength
!= NULL
) {
232 txn
->p_rdlength
= txn
->p
;
238 dns_rdlength_end(dns_towire_state_t
*NONNULL txn
)
242 if (txn
->p_rdlength
== NULL
) {
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
;
254 dns_rdata_a_to_wire(dns_towire_state_t
*NONNULL txn
,
255 const char *NONNULL ip_address
)
258 if (txn
->p
+ 4 >= txn
->lim
) {
259 txn
->error
= ENOBUFS
;
262 if (!inet_pton(AF_INET
, ip_address
, txn
->p
)) {
270 dns_rdata_aaaa_to_wire(dns_towire_state_t
*NONNULL txn
,
271 const char *NONNULL ip_address
)
274 if (txn
->p
+ 16 >= txn
->lim
) {
275 txn
->error
= ENOBUFS
;
278 if (!inet_pton(AF_INET6
, ip_address
, txn
->p
)) {
286 dns_rdata_key_to_wire(dns_towire_state_t
*NONNULL txn
,
292 int key_len
= srp_pubkey_length(key
);
293 uint8_t *rdata
= txn
->p
;
298 if (key_type
> 3 || name_type
> 3 || signatory
> 15) {
302 if (txn
->p
+ key_len
+ 4 >= txn
->lim
) {
303 txn
->error
= ENOBUFS
;
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
);
313 rdlen
= txn
->p
- rdata
;
315 // Compute the key tag
317 for (i
= 0; i
< rdlen
; i
++) {
318 key_tag
+= (i
& 1) ? rdata
[i
] : rdata
[i
] << 8;
320 key_tag
+= (key_tag
>> 16) & 0xFFFF;
321 return (uint16_t)(key_tag
& 0xFFFF);
325 dns_rdata_txt_to_wire(dns_towire_state_t
*NONNULL txn
,
326 const char *NONNULL txt_record
)
329 unsigned len
= strlen(txt_record
);
330 if (txn
->p
+ len
+ 1 >= txn
->lim
) {
331 txn
->error
= ENOBUFS
;
335 txn
->error
= ENAMETOOLONG
;
338 *txn
->p
++ = (u_int8_t
)len
;
339 memcpy(txn
->p
, txt_record
, len
);
345 dns_rdata_raw_data_to_wire(dns_towire_state_t
*NONNULL txn
, const void *NONNULL raw_data
, size_t length
)
348 if (txn
->p
+ length
>= txn
->lim
) {
349 txn
->error
= ENOBUFS
;
352 memcpy(txn
->p
, raw_data
, length
);
358 dns_edns0_header_to_wire(dns_towire_state_t
*NONNULL txn
,
365 if (txn
->p
+ 9 >= txn
->lim
) {
366 txn
->error
= ENOBUFS
;
369 *txn
->p
++ = 0; // root label
370 dns_u16_to_wire(txn
, dns_rrtype_opt
);
371 dns_u16_to_wire(txn
, mtu
);
374 *txn
->p
++ = DO
<< 7; // flags (usb)
375 *txn
->p
++ = 0; // flags (lsb, mbz)
380 dns_edns0_option_begin(dns_towire_state_t
*NONNULL txn
)
383 if (txn
->p
+ 2 >= txn
->lim
) {
384 txn
->error
= ENOBUFS
;
387 if (txn
->p_opt
!= NULL
) {
397 dns_edns0_option_end(dns_towire_state_t
*NONNULL txn
)
401 if (txn
->p_opt
== NULL
) {
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;
413 dns_sig0_signature_to_wire(dns_towire_state_t
*NONNULL txn
,
416 dns_name_pointer_t
*NONNULL signer
,
417 const char *NONNULL signer_fqdn
)
419 int siglen
= srp_signature_length(key
);
420 uint8_t *start
, *p_signer
, *p_signature
, *rrstart
= txn
->p
;
429 // 18 SIG RDATA up to signer name
430 // 2 signer name (always a pointer)
432 // signature data (depends on algorithm, e.g. 64 for ECDSASHA256)
433 // so e.g. 93 bytes total
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
);
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
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);
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
454 dns_u16_to_wire(txn
, key_tag
);
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
;
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
);
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.
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
);
473 dns_rdlength_end(txn
);
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
)
483 struct sockaddr_storage s
;
485 struct sockaddr_in sin
;
486 struct sockaddr_in6 sin6
;
488 socklen_t len
, fromlen
;
489 ssize_t rv
, datasize
;
491 if (!txn
->towire
.error
) {
492 memset(&addr
, 0, sizeof addr
);
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
;
504 txn
->towire
.error
= EPROTONOSUPPORT
;
508 addr
.sa
.sa_len
= len
;
511 txn
->sock
= socket(addr
.sa
.sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
513 txn
->towire
.error
= errno
;
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
);
524 txn
->towire
.error
= errno
;
529 datasize
= txn
->towire
.p
- ((u_int8_t
*)txn
->towire
.message
);
530 rv
= sendto(txn
->sock
, txn
->towire
.message
, datasize
, 0, &addr
.sa
, len
);
532 txn
->towire
.error
= errno
;
535 if (rv
!= datasize
) {
536 txn
->towire
.error
= EMSGSIZE
;
539 fromlen
= sizeof from
;
540 rv
= recvfrom(txn
->sock
, txn
->response
, sizeof *txn
->response
, 0, &from
.sa
, &fromlen
);
542 txn
->towire
.error
= errno
;
545 txn
->response_length
= rv
;
551 if (txn
->towire
.error
) {
560 // c-file-style: "bsd"
563 // indent-tabs-mode: nil