1 /* 2 * packet.c -- low-level DNS packet encoding and decoding functions. 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 #include "config.h" 11 12 #include <string.h> 13 14 #include "packet.h" 15 #include "query.h" 16 #include "rdata.h" 17 18 static void 19 encode_dname(query_type *q, domain_type *domain) 20 { 21 while (domain->parent && query_get_dname_offset(q, domain) == 0) { 22 query_put_dname_offset(q, domain, buffer_position(q->packet)); 23 DEBUG(DEBUG_NAME_COMPRESSION, 2, 24 (LOG_INFO, "dname: %s, number: %lu, offset: %u\n", 25 domain_to_string(domain), 26 (unsigned long) domain->number, 27 query_get_dname_offset(q, domain))); 28 buffer_write(q->packet, dname_name(domain_dname(domain)), 29 label_length(dname_name(domain_dname(domain))) + 1U); 30 domain = domain->parent; 31 } 32 if (domain->parent) { 33 DEBUG(DEBUG_NAME_COMPRESSION, 2, 34 (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n", 35 domain_to_string(domain), 36 (unsigned long) domain->number, 37 query_get_dname_offset(q, domain))); 38 assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET); 39 buffer_write_u16(q->packet, 40 0xc000 | query_get_dname_offset(q, domain)); 41 } else { 42 buffer_write_u8(q->packet, 0); 43 } 44 } 45 46 int 47 packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr, uint32_t ttl) 48 { 49 size_t truncation_mark; 50 uint16_t rdlength = 0; 51 size_t rdlength_pos; 52 uint16_t j; 53 54 assert(q); 55 assert(owner); 56 assert(rr); 57 58 /* 59 * If the record does not in fit in the packet the packet size 60 * will be restored to the mark. 61 */ 62 truncation_mark = buffer_position(q->packet); 63 64 encode_dname(q, owner); 65 buffer_write_u16(q->packet, rr->type); 66 buffer_write_u16(q->packet, rr->klass); 67 buffer_write_u32(q->packet, ttl); 68 69 /* Reserve space for rdlength. */ 70 rdlength_pos = buffer_position(q->packet); 71 buffer_skip(q->packet, sizeof(rdlength)); 72 73 for (j = 0; j < rr->rdata_count; ++j) { 74 switch (rdata_atom_wireformat_type(rr->type, j)) { 75 case RDATA_WF_COMPRESSED_DNAME: 76 encode_dname(q, rdata_atom_domain(rr->rdatas[j])); 77 break; 78 case RDATA_WF_UNCOMPRESSED_DNAME: 79 { 80 const dname_type *dname = domain_dname( 81 rdata_atom_domain(rr->rdatas[j])); 82 buffer_write(q->packet, 83 dname_name(dname), dname->name_size); 84 break; 85 } 86 default: 87 buffer_write(q->packet, 88 rdata_atom_data(rr->rdatas[j]), 89 rdata_atom_size(rr->rdatas[j])); 90 break; 91 } 92 } 93 94 if (!query_overflow(q)) { 95 rdlength = (buffer_position(q->packet) - rdlength_pos 96 - sizeof(rdlength)); 97 buffer_write_u16_at(q->packet, rdlength_pos, rdlength); 98 return 1; 99 } else { 100 buffer_set_position(q->packet, truncation_mark); 101 query_clear_dname_offsets(q, truncation_mark); 102 assert(!query_overflow(q)); 103 return 0; 104 } 105 } 106 107 int 108 packet_encode_rrset(query_type *query, 109 domain_type *owner, 110 rrset_type *rrset, 111 int section, 112 #ifdef MINIMAL_RESPONSES 113 size_t minimal_respsize, 114 int* done) 115 #else 116 size_t ATTR_UNUSED(minimal_respsize), 117 int* ATTR_UNUSED(done)) 118 #endif 119 { 120 uint16_t i; 121 size_t truncation_mark; 122 uint16_t added = 0; 123 int all_added = 1; 124 #ifdef MINIMAL_RESPONSES 125 int minimize_response = (section >= OPTIONAL_AUTHORITY_SECTION); 126 int truncate_rrset = (section == ANSWER_SECTION || 127 section == AUTHORITY_SECTION); 128 #else 129 int truncate_rrset = (section == ANSWER_SECTION || 130 section == AUTHORITY_SECTION || 131 section == OPTIONAL_AUTHORITY_SECTION); 132 #endif 133 rrset_type *rrsig; 134 135 assert(rrset->rr_count > 0); 136 137 truncation_mark = buffer_position(query->packet); 138 139 for (i = 0; i < rrset->rr_count; ++i) { 140 if (packet_encode_rr(query, owner, &rrset->rrs[i], 141 rrset->rrs[i].ttl)) { 142 ++added; 143 } else { 144 all_added = 0; 145 break; 146 } 147 } 148 149 if (all_added && 150 query->edns.dnssec_ok && 151 zone_is_secure(rrset->zone) && 152 rrset_rrtype(rrset) != TYPE_RRSIG && 153 (rrsig = domain_find_rrset(owner, rrset->zone, TYPE_RRSIG))) 154 { 155 for (i = 0; i < rrsig->rr_count; ++i) { 156 if (rr_rrsig_type_covered(&rrsig->rrs[i]) 157 == rrset_rrtype(rrset)) 158 { 159 if (packet_encode_rr(query, owner, 160 &rrsig->rrs[i], 161 rrset_rrtype(rrset)==TYPE_SOA?rrset->rrs[0].ttl:rrsig->rrs[i].ttl)) 162 { 163 ++added; 164 } else { 165 all_added = 0; 166 break; 167 } 168 } 169 } 170 } 171 172 #ifdef MINIMAL_RESPONSES 173 if ((!all_added || buffer_position(query->packet) > minimal_respsize) 174 && !query->tcp && minimize_response) { 175 /* Truncate entire RRset. */ 176 buffer_set_position(query->packet, truncation_mark); 177 query_clear_dname_offsets(query, truncation_mark); 178 added = 0; 179 *done = 1; 180 } 181 #endif 182 183 if (!all_added && truncate_rrset) { 184 /* Truncate entire RRset and set truncate flag. */ 185 buffer_set_position(query->packet, truncation_mark); 186 query_clear_dname_offsets(query, truncation_mark); 187 TC_SET(query->packet); 188 added = 0; 189 } 190 191 return added; 192 } 193 194 int 195 packet_skip_dname(buffer_type *packet) 196 { 197 while (1) { 198 uint8_t label_size; 199 if (!buffer_available(packet, 1)) 200 return 0; 201 202 label_size = buffer_read_u8(packet); 203 if (label_size == 0) { 204 return 1; 205 } else if ((label_size & 0xc0) != 0) { 206 if (!buffer_available(packet, 1)) 207 return 0; 208 buffer_skip(packet, 1); 209 return 1; 210 } else if (!buffer_available(packet, label_size)) { 211 return 0; 212 } else { 213 buffer_skip(packet, label_size); 214 } 215 } 216 } 217 218 int 219 packet_skip_rr(buffer_type *packet, int question_section) 220 { 221 if (!packet_skip_dname(packet)) 222 return 0; 223 224 if (question_section) { 225 if (!buffer_available(packet, 4)) 226 return 0; 227 buffer_skip(packet, 4); 228 } else { 229 uint16_t rdata_size; 230 if (!buffer_available(packet, 10)) 231 return 0; 232 buffer_skip(packet, 8); 233 rdata_size = buffer_read_u16(packet); 234 if (!buffer_available(packet, rdata_size)) 235 return 0; 236 buffer_skip(packet, rdata_size); 237 } 238 239 return 1; 240 } 241 242 rr_type * 243 packet_read_rr(region_type *region, domain_table_type *owners, 244 buffer_type *packet, int question_section) 245 { 246 const dname_type *owner; 247 uint16_t rdlength; 248 ssize_t rdata_count; 249 rdata_atom_type *rdatas; 250 rr_type *result = (rr_type *) region_alloc(region, sizeof(rr_type)); 251 252 owner = dname_make_from_packet(region, packet, 1, 1); 253 if (!owner || !buffer_available(packet, 2*sizeof(uint16_t))) { 254 return NULL; 255 } 256 257 result->owner = domain_table_insert(owners, owner); 258 result->type = buffer_read_u16(packet); 259 result->klass = buffer_read_u16(packet); 260 261 if (question_section) { 262 result->ttl = 0; 263 result->rdata_count = 0; 264 result->rdatas = NULL; 265 return result; 266 } else if (!buffer_available(packet, sizeof(uint32_t) + sizeof(uint16_t))) { 267 return NULL; 268 } 269 270 result->ttl = buffer_read_u32(packet); 271 rdlength = buffer_read_u16(packet); 272 273 if (!buffer_available(packet, rdlength)) { 274 return NULL; 275 } 276 277 rdata_count = rdata_wireformat_to_rdata_atoms( 278 region, owners, result->type, rdlength, packet, &rdatas); 279 if (rdata_count == -1) { 280 return NULL; 281 } 282 result->rdata_count = rdata_count; 283 result->rdatas = rdatas; 284 285 return result; 286 } 287 288 int packet_read_query_section(buffer_type *packet, 289 uint8_t* dst, uint16_t* qtype, uint16_t* qclass) 290 { 291 uint8_t *query_name = buffer_current(packet); 292 uint8_t *src = query_name; 293 size_t len; 294 295 while (*src) { 296 /* 297 * If we are out of buffer limits or we have a pointer 298 * in question dname or the domain name is longer than 299 * MAXDOMAINLEN ... 300 */ 301 if ((*src & 0xc0) || 302 (src + *src + 2 > buffer_end(packet)) || 303 (src + *src + 2 > query_name + MAXDOMAINLEN)) 304 { 305 return 0; 306 } 307 memcpy(dst, src, *src + 1); 308 dst += *src + 1; 309 src += *src + 1; 310 } 311 *dst++ = *src++; 312 313 /* Make sure name is not too long or we have stripped packet... */ 314 len = src - query_name; 315 if (len > MAXDOMAINLEN || 316 (src + 2*sizeof(uint16_t) > buffer_end(packet))) 317 { 318 return 0; 319 } 320 buffer_set_position(packet, src - buffer_begin(packet)); 321 322 *qtype = buffer_read_u16(packet); 323 *qclass = buffer_read_u16(packet); 324 return 1; 325 } 326