]>
git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/towire.c
3 * Copyright (c) 2018-2019 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 to-wire wire-format functions.
19 * These are really simple functions for constructing DNS messages in 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.
32 #ifndef THREAD_DEVKIT_ADK
33 #include <arpa/inet.h>
39 #include "srp-crypto.h"
46 dns_parse_label(const char *cur
, const char *NONNULL
*NONNULL nextp
, uint8_t *NONNULL lenp
, uint8_t *NONNULL buf
,
54 end
= strchr(cur
, '.');
56 end
= cur
+ strlen(cur
);
70 // Figure out the length of the label after escapes have been converted.
72 for (s
= cur
; s
< end
; s
++) {
91 // Is the label too long?
92 if (end
- cur
> DNS_MAX_LABEL_SIZE
) {
96 // Store the label length
97 *lenp
= (uint8_t)(tlen
);
101 for (s
= cur
; s
< end
; s
++) {
107 int val
= v0
* 100 + v1
* 10 + v2
;
124 // Convert a name to wire format. Does not store the root label (0) at the end. Does not support binary labels.
126 dns_name_to_wire_(dns_name_pointer_t
*NULLABLE r_pointer
, dns_towire_state_t
*NONNULL txn
,
127 const char *NONNULL name
, int line
)
129 const char *next
, *cur
;
131 dns_name_pointer_t np
;
134 memset(&np
, 0, sizeof np
);
135 np
.message_start
= (uint8_t *)txn
->message
;
136 np
.name_start
= txn
->p
;
140 // Note that nothing is stored through txn->p until dns_name_parse has verified that
141 // there is space in the buffer for the label as well as the length.
142 status
= dns_parse_label(cur
, &next
, txn
->p
, txn
->p
+ 1, txn
->lim
- txn
->p
- 1);
144 if (status
== ENOBUFS
) {
145 txn
->truncated
= true;
152 // Don't use the root label if it was parsed.
155 np
.length
+= 1 + *txn
->p
;
156 txn
->p
= txn
->p
+ *txn
->p
+ 1;
159 } while (next
!= NULL
);
161 if (np
.length
> DNS_MAX_NAME_SIZE
) {
162 txn
->error
= ENAMETOOLONG
;
166 if (r_pointer
!= NULL
) {
172 // Like dns_name_to_wire, but includes the root label at the end.
174 dns_full_name_to_wire_(dns_name_pointer_t
*NULLABLE r_pointer
, dns_towire_state_t
*NONNULL txn
,
175 const char *NONNULL name
, int line
)
177 dns_name_pointer_t np
;
179 memset(&np
, 0, sizeof np
);
180 dns_name_to_wire(&np
, txn
, name
);
182 if (txn
->p
+ 1 >= txn
->lim
) {
183 txn
->error
= ENOBUFS
;
184 txn
->truncated
= true;
191 if (np
.length
> DNS_MAX_NAME_SIZE
) {
192 txn
->error
= ENAMETOOLONG
;
203 // Store a pointer to a name that's already in the message.
205 dns_pointer_to_wire_(dns_name_pointer_t
*NULLABLE r_pointer
, dns_towire_state_t
*NONNULL txn
,
206 dns_name_pointer_t
*NONNULL pointer
, int line
)
209 uint16_t offset
= pointer
->name_start
- pointer
->message_start
;
210 if (offset
> DNS_MAX_POINTER
) {
211 txn
->error
= ETOOMANYREFS
;
215 if (txn
->p
+ 2 >= txn
->lim
) {
216 txn
->error
= ENOBUFS
;
217 txn
->truncated
= true;
221 *txn
->p
++ = 0xc0 | (offset
>> 8);
222 *txn
->p
++ = offset
& 0xff;
224 r_pointer
->num_labels
+= pointer
->num_labels
;
225 r_pointer
->length
+= pointer
->length
+ 1;
226 if (r_pointer
->length
> DNS_MAX_NAME_SIZE
) {
227 txn
->error
= ENAMETOOLONG
;
236 dns_u8_to_wire_(dns_towire_state_t
*NONNULL txn
, uint8_t val
, int line
)
239 if (txn
->p
+ 1 >= txn
->lim
) {
240 txn
->error
= ENOBUFS
;
241 txn
->truncated
= true;
249 // Store a 16-bit integer in network byte order
251 dns_u16_to_wire_(dns_towire_state_t
*NONNULL txn
, uint16_t val
, int line
)
254 if (txn
->p
+ 2 >= txn
->lim
) {
255 txn
->error
= ENOBUFS
;
256 txn
->truncated
= true;
260 *txn
->p
++ = val
>> 8;
261 *txn
->p
++ = val
& 0xff;
266 dns_u32_to_wire_(dns_towire_state_t
*NONNULL txn
, uint32_t val
, int line
)
269 if (txn
->p
+ 4 >= txn
->lim
) {
270 txn
->error
= ENOBUFS
;
271 txn
->truncated
= true;
275 *txn
->p
++ = val
>> 24;
276 *txn
->p
++ = (val
>> 16) & 0xff;
277 *txn
->p
++ = (val
>> 8) & 0xff;
278 *txn
->p
++ = val
& 0xff;
283 dns_ttl_to_wire_(dns_towire_state_t
*NONNULL txn
, int32_t val
, int line
)
286 dns_u32_to_wire_(txn
, (uint32_t)val
, line
);
291 dns_rdlength_begin_(dns_towire_state_t
*NONNULL txn
, int line
)
294 if (txn
->p
+ 2 >= txn
->lim
) {
295 txn
->error
= ENOBUFS
;
296 txn
->truncated
= true;
300 if (txn
->p_rdlength
!= NULL
) {
305 txn
->p_rdlength
= txn
->p
;
311 dns_rdlength_end_(dns_towire_state_t
*NONNULL txn
, int line
)
315 if (txn
->p_rdlength
== NULL
) {
320 rdlength
= txn
->p
- txn
->p_rdlength
- 2;
321 txn
->p_rdlength
[0] = rdlength
>> 8;
322 txn
->p_rdlength
[1] = rdlength
& 0xff;
323 txn
->p_rdlength
= NULL
;
327 #ifndef THREAD_DEVKIT_ADK
329 dns_rdata_a_to_wire_(dns_towire_state_t
*NONNULL txn
, const char *NONNULL ip_address
, int line
)
332 if (txn
->p
+ 4 >= txn
->lim
) {
333 txn
->error
= ENOBUFS
;
334 txn
->truncated
= true;
338 if (!inet_pton(AF_INET
, ip_address
, txn
->p
)) {
348 dns_rdata_aaaa_to_wire_(dns_towire_state_t
*NONNULL txn
, const char *NONNULL ip_address
, int line
)
351 if (txn
->p
+ 16 >= txn
->lim
) {
352 txn
->error
= ENOBUFS
;
353 txn
->truncated
= true;
357 if (!inet_pton(AF_INET6
, ip_address
, txn
->p
)) {
368 dns_rdata_key_to_wire_(dns_towire_state_t
*NONNULL txn
, unsigned key_type
, unsigned name_type
,
369 unsigned signatory
, srp_key_t
*key
, int line
)
371 ssize_t key_len
= srp_pubkey_length(key
), copied_len
;
372 uint8_t *rdata
= txn
->p
;
378 if (key_type
> 3 || name_type
> 3 || signatory
> 15) {
383 if (txn
->p
+ key_len
+ 4 >= txn
->lim
) {
384 txn
->error
= ENOBUFS
;
385 txn
->truncated
= true;
389 *txn
->p
++ = (key_type
<< 6) | name_type
;
390 *txn
->p
++ = signatory
;
391 *txn
->p
++ = 3; // protocol type is always 3
392 *txn
->p
++ = srp_key_algorithm(key
);
393 copied_len
= srp_pubkey_copy(txn
->p
, key_len
, key
);
394 if (copied_len
== 0) {
401 rdlen
= txn
->p
- rdata
;
403 // Compute the key tag
405 for (i
= 0; i
< rdlen
; i
++) {
406 key_tag
+= (i
& 1) ? rdata
[i
] : rdata
[i
] << 8;
408 key_tag
+= (key_tag
>> 16) & 0xFFFF;
409 return (uint16_t)(key_tag
& 0xFFFF);
413 dns_rdata_txt_to_wire_(dns_towire_state_t
*NONNULL txn
, const char *NONNULL txt_record
, int line
)
416 ssize_t len
= strlen(txt_record
);
417 if (txn
->p
+ len
+ 1 >= txn
->lim
) {
418 txn
->error
= ENOBUFS
;
419 txn
->truncated
= true;
424 txn
->error
= ENAMETOOLONG
;
428 *txn
->p
++ = (uint8_t)len
;
429 memcpy(txn
->p
, txt_record
, len
);
435 dns_rdata_raw_data_to_wire_(dns_towire_state_t
*NONNULL txn
, const void *NONNULL raw_data
, size_t length
, int line
)
438 if (txn
->p
+ length
>= txn
->lim
) {
439 txn
->error
= ENOBUFS
;
440 txn
->truncated
= true;
444 memcpy(txn
->p
, raw_data
, length
);
450 dns_edns0_header_to_wire_(dns_towire_state_t
*NONNULL txn
, int mtu
, int xrcode
, int version
, int DO
, int line
)
453 if (txn
->p
+ 9 >= txn
->lim
) {
454 txn
->error
= ENOBUFS
;
455 txn
->truncated
= true;
459 *txn
->p
++ = 0; // root label
460 dns_u16_to_wire(txn
, dns_rrtype_opt
);
461 dns_u16_to_wire(txn
, mtu
);
464 *txn
->p
++ = DO
<< 7; // flags (usb)
465 *txn
->p
++ = 0; // flags (lsb, mbz)
470 dns_edns0_option_begin_(dns_towire_state_t
*NONNULL txn
, int line
)
473 if (txn
->p
+ 2 >= txn
->lim
) {
474 txn
->error
= ENOBUFS
;
475 txn
->truncated
= true;
479 if (txn
->p_opt
!= NULL
) {
490 dns_edns0_option_end_(dns_towire_state_t
*NONNULL txn
, int line
)
494 if (txn
->p_opt
== NULL
) {
499 opt_length
= txn
->p
- txn
->p_opt
- 2;
500 txn
->p_opt
[0] = opt_length
>> 8;
501 txn
->p_opt
[1] = opt_length
& 0xff;
507 dns_sig0_signature_to_wire_(dns_towire_state_t
*NONNULL txn
, srp_key_t
*key
, uint16_t key_tag
,
508 dns_name_pointer_t
*NONNULL signer
, const char *NONNULL signer_hostname
,
509 const char *NONNULL signer_domain
, int line
)
511 ssize_t siglen
= srp_signature_length(key
);
512 uint8_t *start
, *p_signer
, *p_signature
, *rrstart
= txn
->p
;
521 // 18 SIG RDATA up to signer name
522 // 2 signer name (always a pointer)
524 // signature data (depends on algorithm, e.g. 64 for ECDSASHA256)
525 // so e.g. 93 bytes total
528 dns_u8_to_wire(txn
, 0); // root label
529 dns_u16_to_wire(txn
, dns_rrtype_sig
);
530 dns_u16_to_wire(txn
, 0); // class
531 dns_ttl_to_wire(txn
, 0); // SIG RR TTL
532 dns_rdlength_begin(txn
);
534 dns_u16_to_wire(txn
, 0); // type = 0 for transaction signature
535 dns_u8_to_wire(txn
, srp_key_algorithm(key
));
536 dns_u8_to_wire(txn
, 0); // labels field doesn't apply for transaction signature
537 dns_ttl_to_wire(txn
, 0); // original ttl doesn't apply
539 gettimeofday(&now
, NULL
);
540 uint32_t sec
= (uint32_t)now
.tv_sec
;
541 // In te extraordinarily unlikely event that time_t has rolled over
544 dns_u32_to_wire(txn
, 0); // Indicate that we have no clock: set expiry and inception times to zero
545 dns_u32_to_wire(txn
, 0);
548 dns_u32_to_wire(txn
, sec
+ 300); // signature expiration time is five minutes from now
549 dns_u32_to_wire(txn
, sec
- 300); // signature inception time, five minutes in the past
552 dns_u16_to_wire(txn
, key_tag
);
555 // We store the name in uncompressed form because that's what we have to sign
556 if (signer_hostname
!= NULL
) {
557 dns_name_to_wire(NULL
, txn
, signer_hostname
);
559 dns_full_name_to_wire(NULL
, txn
, signer_domain
);
560 // And that means we're going to have to copy the signature back earlier in the packet.
561 p_signature
= txn
->p
;
563 // Sign the message, signature RRDATA (less signature) first.
564 if (!srp_sign(txn
->p
, siglen
, (uint8_t *)txn
->message
, rrstart
- (uint8_t *)txn
->message
,
565 start
, txn
->p
- start
, key
)) {
567 txn
->line
= __LINE__
;
569 // Now that it's signed, back up and store the pointer to the name, because we're trying
570 // to be as compact as possible.
572 dns_pointer_to_wire(NULL
, txn
, signer
); // Pointer to the owner name the key is attached to
573 // And move the signature earlier in the packet.
574 memmove(txn
->p
, p_signature
, siglen
);
577 dns_rdlength_end(txn
);
581 txn
->outer_line
= line
;
586 #ifdef MALLOC_DEBUG_LOGGING
593 debug_malloc(size_t len
, const char *file
, int line
)
595 void *ret
= malloc(len
);
596 INFO("%p: malloc(%zu) at " PUB_S_SRP
":%d", ret
, len
, file
, line
);
601 debug_calloc(size_t count
, size_t len
, const char *file
, int line
)
603 void *ret
= calloc(count
, len
);
604 INFO("%p: calloc(%zu, %zu) at " PUB_S_SRP
":%d", ret
, count
, len
, file
, line
);
609 debug_strdup(const char *s
, const char *file
, int line
)
611 char *ret
= strdup(s
);
612 INFO("%p: strdup(%p) at " PUB_S_SRP
":%d", ret
, s
, file
, line
);
617 debug_free(void *p
, const char *file
, int line
)
619 INFO("%p: free() at " PUB_S_SRP
":%d", p
, file
, line
);
627 // c-file-style: "bsd"
630 // indent-tabs-mode: nil