Home | History | Annotate | Line # | Download | only in objs
      1 /*
      2  * Copyright (c) 2022 Apple Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     https://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //======================================================================================================================
     18 // MARK: - Headers
     19 
     20 #include "dns_obj_log.h"
     21 #include "dns_obj_rr_private.h"
     22 #include "domain_name_labels.h"
     23 #include "dns_common.h"
     24 #include <string.h>	// For memcmp().
     25 
     26 #include "dns_assert_macros.h"
     27 #include "mdns_strict.h"
     28 
     29 //======================================================================================================================
     30 // MARK: - DNS Resource Record Kind Definition
     31 
     32 // The definition of the resource record object is in `dns_obj_rr_private.h`
     33 DNS_OBJECT_DEFINE_FULL(rr);
     34 
     35 //======================================================================================================================
     36 // MARK: - Local Prototypes
     37 
     38 static uint8_t *
     39 dns_obj_rr_create_signed_data(dns_obj_rr_t NONNULL me, size_t * NONNULL signed_data_len);
     40 
     41 //======================================================================================================================
     42 // MARK: - DNSSEC Resource Record Public Methods
     43 
     44 dns_obj_rr_t
     45 dns_obj_rr_create(const uint8_t * const name, const uint16_t type, const uint16_t class,
     46 	const uint8_t * const rdata, const uint16_t rdata_len, const bool allocate_memory, dns_obj_error_t * const out_error)
     47 {
     48 	dns_obj_error_t err;
     49 	dns_obj_rr_t record = NULL;
     50 	dns_obj_rr_t obj = NULL;
     51 
     52 	obj = _dns_obj_rr_new();
     53 	require_action(obj != NULL, exit, err = DNS_OBJ_ERROR_NO_MEMORY);
     54 
     55 	dns_obj_rr_init_fields(obj, name, type, class, rdata, rdata_len, allocate_memory, NULL, &err);
     56 	require_noerr(err, exit);
     57 
     58 	record = obj;
     59 	obj = NULL;
     60 	err = DNS_OBJ_ERROR_NO_ERROR;
     61 
     62 exit:
     63 	if (out_error != NULL) {
     64 		*out_error = err;
     65 	}
     66 	MDNS_DISPOSE_DNS_OBJ(obj);
     67 	return record;
     68 }
     69 
     70 //======================================================================================================================
     71 
     72 dns_obj_domain_name_t
     73 dns_obj_rr_get_name(const dns_obj_rr_t me)
     74 {
     75 	return me->name;
     76 }
     77 
     78 //======================================================================================================================
     79 
     80 const uint8_t *
     81 dns_obj_rr_get_name_in_labels(const dns_obj_rr_t me)
     82 {
     83 	const dns_obj_domain_name_t name = me->name;
     84 	return dns_obj_domain_name_get_labels(name);
     85 }
     86 
     87 //======================================================================================================================
     88 
     89 uint16_t
     90 dns_obj_rr_get_type(const dns_obj_rr_t me)
     91 {
     92 	return me->type;
     93 }
     94 
     95 //======================================================================================================================
     96 
     97 uint16_t
     98 dns_obj_rr_get_class(const dns_obj_rr_t me)
     99 {
    100 	return me->class;
    101 }
    102 
    103 //======================================================================================================================
    104 
    105 uint16_t
    106 dns_obj_rr_get_rdata_len(const dns_obj_rr_t me)
    107 {
    108 	return me->rdata_len;
    109 }
    110 
    111 //======================================================================================================================
    112 
    113 const uint8_t *
    114 dns_obj_rr_get_rdata(const dns_obj_rr_t me)
    115 {
    116 	if (!me->allocated_memory) {
    117 		return me->rdata_u.const_rdata;
    118 	} else {
    119 		return me->rdata_u.allocated_rdata;
    120 	}
    121 }
    122 
    123 //======================================================================================================================
    124 
    125 uint32_t
    126 dns_obj_rr_get_ttl(const dns_obj_rr_t me)
    127 {
    128 	return me->ttl;
    129 }
    130 
    131 //======================================================================================================================
    132 
    133 const uint8_t *
    134 dns_obj_rr_get_signed_data(const dns_obj_rr_t me)
    135 {
    136 	if (me->signed_data == NULL) {
    137 		size_t signed_data_len;
    138 		me->signed_data = dns_obj_rr_create_signed_data(me, &signed_data_len);
    139 		if (me->signed_data != NULL) {
    140 			me->signed_data_len = signed_data_len;
    141 		}
    142 	}
    143 
    144 	return me->signed_data;
    145 }
    146 
    147 //======================================================================================================================
    148 
    149 size_t
    150 dns_obj_rr_get_signed_data_len(const dns_obj_rr_t me)
    151 {
    152 	// Call dns_obj_rr_get_signed_data() will also set signed_data_len.
    153 	dns_obj_rr_get_signed_data(me);
    154 	return me->signed_data_len;
    155 }
    156 
    157 //======================================================================================================================
    158 
    159 char *
    160 dns_obj_rr_copy_rdata_rfc_description(const dns_obj_rr_t me, dns_obj_error_t * const out_error)
    161 {
    162 	if (me->copy_rdata_rfc_description_method != NULL) {
    163 		return me->copy_rdata_rfc_description_method(me, out_error);
    164 	}
    165 
    166 	// "65535 <Hex Dump>"
    167 	dns_obj_error_t err;
    168 	const size_t max_len = strlen("65535") + 1 + 2 * dns_obj_rr_get_rdata_len(me) + 1;
    169 	char *buffer = mdns_calloc(1, max_len);
    170 	require_action(buffer != NULL, exit, err = DNS_OBJ_ERROR_NO_MEMORY);
    171 
    172 	char *ptr = buffer;
    173 	const char * const limit = buffer + max_len;
    174 	ptr += snprintf(ptr, (size_t)(limit - ptr), "%u ", dns_obj_rr_get_rdata_len(me));
    175 
    176 	const char * const end = put_hex_from_bytes(dns_obj_rr_get_rdata(me), dns_obj_rr_get_rdata_len(me), ptr, (size_t)(limit - ptr));
    177 	require_action(end != ptr, exit, err = DNS_OBJ_ERROR_OVER_RUN);
    178 	err = DNS_OBJ_ERROR_NO_ERROR;
    179 
    180 exit:
    181 	if (out_error != NULL) {
    182 		*out_error = err;
    183 	}
    184 	return buffer;
    185 }
    186 
    187 //======================================================================================================================
    188 
    189 void
    190 dns_obj_rr_clear_comparison_attributes(const dns_obj_rr_t me)
    191 {
    192 	me->original_ttl = 0;
    193 	me->rrsig_labels = 0;
    194 	me->signed_data_len = 0;
    195 	mdns_free(me->signed_data);
    196 }
    197 
    198 //======================================================================================================================
    199 
    200 void
    201 dns_obj_rr_set_comparison_attributes(const dns_obj_rr_t me, const uint32_t original_ttl, const uint8_t rrsig_labels)
    202 {
    203 	me->original_ttl = original_ttl;
    204 	me->rrsig_labels = rrsig_labels;
    205 }
    206 
    207 //======================================================================================================================
    208 
    209 void
    210 dns_obj_rrs_set_comparison_attributes(dns_obj_rr_t * const rrs, const size_t rr_count, const uint32_t original_ttl,
    211 	const uint8_t rrsig_labels)
    212 {
    213 	for (size_t i = 0; i < rr_count; i++) {
    214 		dns_obj_rr_set_comparison_attributes(rrs[i], original_ttl, rrsig_labels);
    215 	}
    216 }
    217 
    218 //======================================================================================================================
    219 
    220 void
    221 dns_obj_rrs_clear_comparison_attributes(dns_obj_rr_t * const rrs, const size_t rr_count)
    222 {
    223 	for (size_t i = 0; i < rr_count; i++) {
    224 		dns_obj_rr_clear_comparison_attributes(rrs[i]);
    225 	}
    226 }
    227 
    228 //======================================================================================================================
    229 
    230 bool
    231 dns_obj_rr_equal_to_raw_data(const dns_obj_rr_t me, const uint8_t * const name, const uint16_t type,
    232 	const uint16_t class, const uint8_t * const rdata, const uint16_t rdata_len)
    233 {
    234 	if (type != dns_obj_rr_get_type(me)) {
    235 		return false;
    236 	}
    237 
    238 	if (class != dns_obj_rr_get_class(me)) {
    239 		return false;
    240 	}
    241 
    242 	if (rdata_len != dns_obj_rr_get_rdata_len(me)) {
    243 		return false;
    244 	}
    245 
    246 	if (domain_name_labels_canonical_compare(name, dns_obj_rr_get_name_in_labels(me), true) != compare_result_equal) {
    247 		return false;
    248 	}
    249 
    250 	const bool points_to_same_memory = (rdata == dns_obj_rr_get_rdata(me));
    251 	if (!points_to_same_memory && memcmp(rdata, dns_obj_rr_get_rdata(me), rdata_len) != 0) {
    252 		return false;
    253 	}
    254 
    255 	return true;
    256 }
    257 
    258 //======================================================================================================================
    259 
    260 bool
    261 dns_obj_rrs_belong_to_one_rrset(dns_obj_rr_t * const rrs, const size_t count)
    262 {
    263 	require_return_value(count > 0, false);
    264 
    265 	const uint16_t class = dns_obj_rr_get_class(rrs[0]);
    266 	const uint16_t type = dns_obj_rr_get_type(rrs[0]);
    267 	const dns_obj_domain_name_t name = dns_obj_rr_get_name(rrs[0]);
    268 
    269 	for (size_t i = 1; i < count; i++) {
    270 		const dns_obj_rr_t rr = rrs[i];
    271 		if (dns_obj_rr_get_class(rr) != class) {
    272 			return false;
    273 		}
    274 		if (dns_obj_rr_get_type(rr) != type) {
    275 			return false;
    276 		}
    277 		if (!dns_obj_equal(dns_obj_rr_get_name(rr), name)) {
    278 			return false;
    279 		}
    280 	}
    281 
    282 	return true;
    283 }
    284 
    285 //======================================================================================================================
    286 // MARK: - DNSSEC Resource Record Private Methods
    287 
    288 static compare_result_t
    289 _dns_obj_rr_compare(const dns_obj_rr_t me, const dns_obj_rr_t other, const bool check_equality_only)
    290 {
    291 	if (check_equality_only) {
    292 		if (me->class != other->class) {
    293 			return compare_result_notequal;
    294 		}
    295 
    296 		if (me->type != other->type) {
    297 			return compare_result_notequal;
    298 		}
    299 
    300 		if (me->rdata_len != other->rdata_len) {
    301 			return compare_result_notequal;
    302 		}
    303 
    304 		if (!dns_obj_equal(me->name, other->name)) {
    305 			return compare_result_notequal;
    306 		}
    307 
    308 		const uint8_t * const my_data = dns_obj_rr_get_rdata(me);
    309 		const uint8_t * const others_data = dns_obj_rr_get_rdata(other);
    310 
    311 		const bool rdata_equal = (memcmp(my_data, others_data, me->rdata_len) == 0);
    312 
    313 		return rdata_equal ? compare_result_equal : compare_result_notequal;
    314 	} else {
    315 
    316 		// <https://datatracker.ietf.org/doc/html/rfc4034#section-6.3> Canonical RR Ordering within an RRset:
    317 		// For the purposes of DNS security, RRs with the same owner name, class, and type are sorted by treating the
    318 		// RDATA portion of the canonical form of each RR as a left-justified unsigned octet sequence in which the
    319 		// absence of an octet sorts before a zero octet.
    320 
    321 		if (!dns_obj_equal(dns_obj_rr_get_name(me), dns_obj_rr_get_name(other))) {
    322 			return compare_result_unknown;
    323 		}
    324 
    325 		if (dns_obj_rr_get_class(me) != dns_obj_rr_get_class(other)) {
    326 			return compare_result_unknown;
    327 		}
    328 
    329 		if (dns_obj_rr_get_type(me) != dns_obj_rr_get_type(other)) {
    330 			return compare_result_unknown;
    331 		}
    332 
    333 		const uint8_t * const my_rdata = dns_obj_rr_get_rdata(me);
    334 		const size_t my_rdata_len = dns_obj_rr_get_rdata_len(me);
    335 		const uint8_t * const others_rdata = dns_obj_rr_get_rdata(other);
    336 		const size_t others_rdata_len = dns_obj_rr_get_rdata_len(other);
    337 		const size_t len_to_compare = MIN(my_rdata_len, others_rdata_len);
    338 
    339 		const int compare_result = memcmp(my_rdata, others_rdata, len_to_compare);
    340 		if (compare_result < 0) {
    341 			return compare_result_less;
    342 		} else if (compare_result > 0) {
    343 			return compare_result_greater;
    344 		} else {
    345 			// The absence of an octet sorts before a zero octet.
    346 			if (my_rdata_len < others_rdata_len) {
    347 				return compare_result_less;
    348 			} else if (my_rdata_len > others_rdata_len) {
    349 				return compare_result_greater;
    350 			} else {
    351 				return compare_result_equal;
    352 			}
    353 		}
    354 	}
    355 }
    356 
    357 //======================================================================================================================
    358 
    359 static void
    360 _dns_obj_rr_finalize(const dns_obj_rr_t me)
    361 {
    362 	MDNS_DISPOSE_DNS_OBJ(me->name);
    363 	if (me->allocated_memory) {
    364 		mdns_free(me->rdata_u.allocated_rdata);
    365 	}
    366 	mdns_free(me->signed_data);
    367 }
    368 
    369 // =====================================================================================================================
    370 // MARK: - Resource Record Project Private Functions
    371 
    372 void
    373 dns_obj_rr_init_fields(const dns_obj_rr_t me, const uint8_t * const name, const uint16_t type,
    374 	const uint16_t class, const uint8_t * const rdata, const uint16_t rdata_len, const bool allocate_memory,
    375 	const dns_obj_rr_copy_rdata_rfc_description_f copy_rdata_rfc_description_method, dns_obj_error_t * const out_error)
    376 {
    377 	dns_obj_error_t err;
    378 	uint8_t *allocated_rdata = NULL;
    379 	dns_obj_domain_name_t name_obj = NULL;
    380 
    381 	name_obj = dns_obj_domain_name_create_with_labels(name, allocate_memory, &err);
    382 	require_noerr(err, exit);
    383 
    384 	me->allocated_memory = allocate_memory;
    385 	if (!me->allocated_memory) {
    386 		me->rdata_u.const_rdata = rdata;
    387 	} else {
    388 		if (rdata_len != 0) {
    389 			require_action(rdata != NULL, exit, err = DNS_OBJ_ERROR_PARAM_ERR);
    390 			allocated_rdata = mdns_malloc(rdata_len);
    391 			require_action(allocated_rdata != NULL, exit, err = DNS_OBJ_ERROR_NO_MEMORY);
    392 			memcpy(allocated_rdata, rdata, rdata_len);
    393 		}
    394 		me->rdata_u.allocated_rdata = allocated_rdata;
    395 		allocated_rdata = NULL;
    396 	}
    397 
    398 	me->name = name_obj;
    399 	name_obj = NULL;
    400 
    401 	me->type = type;
    402 	me->class = class;
    403 	me->rdata_len = rdata_len;
    404 	me->ttl = MAX_UNICAST_TTL_IN_SECONDS;
    405 	me->copy_rdata_rfc_description_method = copy_rdata_rfc_description_method;
    406 	err = DNS_OBJ_ERROR_NO_ERROR;
    407 
    408 exit:
    409 	if (out_error != NULL) {
    410 		*out_error = err;
    411 	}
    412 	mdns_free(allocated_rdata);
    413 	MDNS_DISPOSE_DNS_OBJ(name_obj);
    414 }
    415 
    416 //======================================================================================================================
    417 // MARK: - Local Functions
    418 
    419 static uint8_t *
    420 dns_obj_rr_create_signed_data(const dns_obj_rr_t me, size_t * const out_signed_data_len)
    421 {
    422 	// RR(i) = name | type | class | OrigTTL | RDATA length | RDATA
    423 	dns_obj_error_t err;
    424 	dns_obj_domain_name_t name_to_sign = NULL;
    425 	uint8_t *signed_data = NULL;
    426 
    427 	require_return_value(me->original_ttl != 0, NULL);
    428 
    429 	const dns_obj_domain_name_t name = dns_obj_rr_get_name(me);
    430 	const uint16_t type = dns_obj_rr_get_type(me);
    431 	const uint16_t class = dns_obj_rr_get_class(me);
    432 	const uint16_t rdata_len = dns_obj_rr_get_rdata_len(me);
    433 	const uint32_t original_ttl = me->original_ttl;
    434 
    435 	// Get the name in canonical form.
    436 	name_to_sign = dns_obj_domain_name_create_canonical(name, me->rrsig_labels, &err);
    437 	require_noerr(err, exit);
    438 
    439 	// Pre-calculate the length of the signed data.
    440 	size_t signed_data_len = dns_obj_domain_name_get_length(name_to_sign);
    441 	signed_data_len += sizeof(type);
    442 	signed_data_len += sizeof(class);
    443 	signed_data_len += sizeof(original_ttl);
    444 	signed_data_len += sizeof(rdata_len);
    445 	signed_data_len += rdata_len;
    446 
    447 	signed_data = mdns_malloc(signed_data_len);
    448 	require(signed_data != NULL, exit);
    449 	*out_signed_data_len = signed_data_len;
    450 
    451 	uint8_t *ptr = signed_data;
    452 
    453 	// RR(i) += name
    454 	memcpy(ptr, dns_obj_domain_name_get_labels(name_to_sign), dns_obj_domain_name_get_length(name_to_sign));
    455 	ptr += dns_obj_domain_name_get_length(name_to_sign);
    456 
    457 	// RR(i) += type
    458 	put_uint16_to_bytes(type, &ptr);
    459 
    460 	// RR(i) += class
    461 	put_uint16_to_bytes(class, &ptr);
    462 
    463 	// RR(i) += OrigTTL
    464 	put_uint32_to_bytes(original_ttl, &ptr);
    465 
    466 	// RR(i) += RDATA length
    467 	put_uint16_to_bytes(rdata_len, &ptr);
    468 
    469 	// RR(i) += RDATA
    470 	memcpy(ptr, dns_obj_rr_get_rdata(me), rdata_len);
    471 
    472 exit:
    473 	MDNS_DISPOSE_DNS_OBJ(name_to_sign);
    474 	return signed_data;
    475 }
    476