1 /* 2 * edns.c -- EDNS definitions (RFC 2671). 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 11 #include "config.h" 12 13 #include <string.h> 14 #ifdef HAVE_SSL 15 #include <openssl/opensslv.h> 16 #include <openssl/evp.h> 17 #endif 18 19 #include "dns.h" 20 #include "edns.h" 21 #include "nsd.h" 22 #include "query.h" 23 24 void 25 edns_init_data(edns_data_type *data, uint16_t max_length) 26 { 27 memset(data, 0, sizeof(edns_data_type)); 28 /* record type: OPT */ 29 data->ok[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ 30 data->ok[2] = TYPE_OPT & 0x00ff; /* type_lo */ 31 /* udp payload size */ 32 data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */ 33 data->ok[4] = max_length & 0x00ff; /* size_lo */ 34 35 data->error[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ 36 data->error[2] = TYPE_OPT & 0x00ff; /* type_lo */ 37 data->error[3] = (max_length & 0xff00) >> 8; /* size_hi */ 38 data->error[4] = max_length & 0x00ff; /* size_lo */ 39 data->error[5] = 1; /* XXX Extended RCODE=BAD VERS */ 40 41 /* COOKIE OPT HDR */ 42 data->cookie[0] = (COOKIE_CODE & 0xff00) >> 8; 43 data->cookie[1] = (COOKIE_CODE & 0x00ff); 44 data->cookie[2] = (24 & 0xff00) >> 8; 45 data->cookie[3] = (24 & 0x00ff); 46 } 47 48 void 49 edns_init_nsid(edns_data_type *data, uint16_t nsid_len) 50 { 51 /* NSID OPT HDR */ 52 data->nsid[0] = (NSID_CODE & 0xff00) >> 8; 53 data->nsid[1] = (NSID_CODE & 0x00ff); 54 data->nsid[2] = (nsid_len & 0xff00) >> 8; 55 data->nsid[3] = (nsid_len & 0x00ff); 56 } 57 58 void 59 edns_init_record(edns_record_type *edns) 60 { 61 edns->status = EDNS_NOT_PRESENT; 62 edns->position = 0; 63 edns->maxlen = 0; 64 edns->opt_reserved_space = 0; 65 edns->dnssec_ok = 0; 66 edns->nsid = 0; 67 edns->cookie_status = COOKIE_NOT_PRESENT; 68 edns->cookie_len = 0; 69 edns->ede = -1; /* -1 means no Extended DNS Error */ 70 edns->ede_text = NULL; 71 edns->ede_text_len = 0; 72 } 73 74 /** handle a single edns option in the query */ 75 static int 76 edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, 77 edns_record_type* edns, struct query* query, nsd_type* nsd) 78 { 79 (void) query; /* in case edns options need the query structure */ 80 /* handle opt code and read the optlen bytes from the packet */ 81 switch(optcode) { 82 case NSID_CODE: 83 /* is NSID enabled? */ 84 if(nsd->nsid_len > 0) { 85 edns->nsid = 1; 86 /* we have to check optlen, and move the buffer along */ 87 buffer_skip(packet, optlen); 88 /* in the reply we need space for optcode+optlen+nsid_bytes */ 89 edns->opt_reserved_space += OPT_HDR + nsd->nsid_len; 90 } else { 91 /* ignore option */ 92 buffer_skip(packet, optlen); 93 } 94 break; 95 case COOKIE_CODE: 96 /* Cookies enabled? */ 97 if(nsd->do_answer_cookie) { 98 if (optlen == 8) 99 edns->cookie_status = COOKIE_INVALID; 100 else if (optlen < 16 || optlen > 40) 101 return 0; /* FORMERR */ 102 else 103 edns->cookie_status = COOKIE_UNVERIFIED; 104 105 edns->cookie_len = optlen; 106 memcpy(edns->cookie, buffer_current(packet), optlen); 107 buffer_skip(packet, optlen); 108 edns->opt_reserved_space += OPT_HDR + 24; 109 } else { 110 buffer_skip(packet, optlen); 111 } 112 break; 113 default: 114 buffer_skip(packet, optlen); 115 break; 116 } 117 return 1; 118 } 119 120 int 121 edns_parse_record(edns_record_type *edns, buffer_type *packet, 122 query_type* query, nsd_type* nsd) 123 { 124 /* OPT record type... */ 125 uint8_t opt_owner; 126 uint16_t opt_type; 127 uint16_t opt_class; 128 uint8_t opt_version; 129 uint16_t opt_flags; 130 uint16_t opt_rdlen; 131 132 edns->position = buffer_position(packet); 133 134 if (!buffer_available(packet, (OPT_LEN + OPT_RDATA))) 135 return 0; 136 137 opt_owner = buffer_read_u8(packet); 138 opt_type = buffer_read_u16(packet); 139 if (opt_owner != 0 || opt_type != TYPE_OPT) { 140 /* Not EDNS. */ 141 buffer_set_position(packet, edns->position); 142 return 0; 143 } 144 145 opt_class = buffer_read_u16(packet); 146 (void)buffer_read_u8(packet); /* opt_extended_rcode */ 147 opt_version = buffer_read_u8(packet); 148 opt_flags = buffer_read_u16(packet); 149 opt_rdlen = buffer_read_u16(packet); 150 151 if (opt_version != 0) { 152 /* The only error is VERSION not implemented */ 153 edns->status = EDNS_ERROR; 154 return 1; 155 } 156 157 if (opt_rdlen > 0) { 158 if(!buffer_available(packet, opt_rdlen)) 159 return 0; 160 if(opt_rdlen > 65530) 161 return 0; 162 /* there is more to come, read opt code */ 163 while(opt_rdlen >= 4) { 164 uint16_t optcode = buffer_read_u16(packet); 165 uint16_t optlen = buffer_read_u16(packet); 166 opt_rdlen -= 4; 167 if(opt_rdlen < optlen) 168 return 0; /* opt too long, formerr */ 169 opt_rdlen -= optlen; 170 if(!edns_handle_option(optcode, optlen, packet, 171 edns, query, nsd)) 172 return 0; 173 } 174 if(opt_rdlen != 0) 175 return 0; 176 } 177 178 edns->status = EDNS_OK; 179 edns->maxlen = opt_class; 180 edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK; 181 return 1; 182 } 183 184 size_t 185 edns_reserved_space(edns_record_type *edns) 186 { 187 /* MIEK; when a pkt is too large?? */ 188 return edns->status == EDNS_NOT_PRESENT ? 0 189 : (OPT_LEN + OPT_RDATA + edns->opt_reserved_space); 190 } 191 192 int siphash(const uint8_t *in, const size_t inlen, 193 const uint8_t *k, uint8_t *out, const size_t outlen); 194 195 /** RFC 1982 comparison, uses unsigned integers, and tries to avoid 196 * compiler optimization (eg. by avoiding a-b<0 comparisons), 197 * this routine matches compare_serial(), for SOA serial number checks */ 198 static int 199 compare_1982(uint32_t a, uint32_t b) 200 { 201 /* for 32 bit values */ 202 const uint32_t cutoff = ((uint32_t) 1 << (32 - 1)); 203 204 if (a == b) { 205 return 0; 206 } else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) { 207 return -1; 208 } else { 209 return 1; 210 } 211 } 212 213 /** if we know that b is larger than a, return the difference between them, 214 * that is the distance between them. in RFC1982 arith */ 215 static uint32_t 216 subtract_1982(uint32_t a, uint32_t b) 217 { 218 /* for 32 bit values */ 219 const uint32_t cutoff = ((uint32_t) 1 << (32 - 1)); 220 221 if(a == b) 222 return 0; 223 if(a < b && b - a < cutoff) { 224 return b-a; 225 } 226 if(a > b && a - b > cutoff) { 227 return ((uint32_t)0xffffffff) - (a-b-1); 228 } 229 /* wrong case, b smaller than a */ 230 return 0; 231 } 232 233 void cookie_verify(query_type *q, struct nsd* nsd, uint32_t *now_p) { 234 uint8_t hash[8], hash2verify[8]; 235 uint32_t cookie_time, now_uint32; 236 size_t verify_size; 237 int i; 238 239 /* We support only draft-sury-toorop-dnsop-server-cookies sizes */ 240 if(q->edns.cookie_len != 24) 241 return; 242 243 if(q->edns.cookie[8] != 1) 244 return; 245 246 q->edns.cookie_status = COOKIE_INVALID; 247 248 cookie_time = (q->edns.cookie[12] << 24) 249 | (q->edns.cookie[13] << 16) 250 | (q->edns.cookie[14] << 8) 251 | q->edns.cookie[15]; 252 253 now_uint32 = *now_p ? *now_p : (*now_p = (uint32_t)time(NULL)); 254 255 if(compare_1982(now_uint32, cookie_time) > 0) { 256 /* ignore cookies > 1 hour in past */ 257 if (subtract_1982(cookie_time, now_uint32) > 3600) 258 return; 259 } else if (subtract_1982(now_uint32, cookie_time) > 300) { 260 /* ignore cookies > 5 minutes in future */ 261 return; 262 } 263 264 memcpy(hash2verify, q->edns.cookie + 16, 8); 265 266 #ifdef INET6 267 if(q->addr.ss_family == AF_INET6) { 268 memcpy(q->edns.cookie + 16, &((struct sockaddr_in6 *)&q->addr)->sin6_addr, 16); 269 verify_size = 32; 270 } else { 271 memcpy(q->edns.cookie + 16, &((struct sockaddr_in *)&q->addr)->sin_addr, 4); 272 verify_size = 20; 273 } 274 #else 275 memcpy( q->edns.cookie + 16, &q->addr.sin_addr, 4); 276 verify_size = 20; 277 #endif 278 279 q->edns.cookie_status = COOKIE_INVALID; 280 siphash(q->edns.cookie, verify_size, 281 nsd->cookie_secrets[0].cookie_secret, hash, 8); 282 if(CRYPTO_memcmp(hash2verify, hash, 8) == 0 ) { 283 if (subtract_1982(cookie_time, now_uint32) < 1800) { 284 q->edns.cookie_status = COOKIE_VALID_REUSE; 285 memcpy(q->edns.cookie + 16, hash, 8); 286 } else 287 q->edns.cookie_status = COOKIE_VALID; 288 return; 289 } 290 for(i = 1; 291 i < (int)nsd->cookie_count && i < NSD_COOKIE_HISTORY_SIZE; 292 i++) { 293 siphash(q->edns.cookie, verify_size, 294 nsd->cookie_secrets[i].cookie_secret, hash, 8); 295 if(CRYPTO_memcmp(hash2verify, hash, 8) == 0 ) { 296 q->edns.cookie_status = COOKIE_VALID; 297 return; 298 } 299 } 300 } 301 302 void cookie_create(query_type *q, struct nsd* nsd, uint32_t *now_p) 303 { 304 uint8_t hash[8]; 305 uint32_t now_uint32; 306 307 if (q->edns.cookie_status == COOKIE_VALID_REUSE) 308 return; 309 310 now_uint32 = *now_p ? *now_p : (*now_p = (uint32_t)time(NULL)); 311 q->edns.cookie[ 8] = 1; 312 q->edns.cookie[ 9] = 0; 313 q->edns.cookie[10] = 0; 314 q->edns.cookie[11] = 0; 315 q->edns.cookie[12] = (now_uint32 & 0xFF000000) >> 24; 316 q->edns.cookie[13] = (now_uint32 & 0x00FF0000) >> 16; 317 q->edns.cookie[14] = (now_uint32 & 0x0000FF00) >> 8; 318 q->edns.cookie[15] = now_uint32 & 0x000000FF; 319 #ifdef INET6 320 if (q->addr.ss_family == AF_INET6) { 321 memcpy( q->edns.cookie + 16 322 , &((struct sockaddr_in6 *)&q->addr)->sin6_addr, 16); 323 siphash(q->edns.cookie, 32, nsd->cookie_secrets[0].cookie_secret, hash, 8); 324 } else { 325 memcpy( q->edns.cookie + 16 326 , &((struct sockaddr_in *)&q->addr)->sin_addr, 4); 327 siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8); 328 } 329 #else 330 memcpy( q->edns.cookie + 16, &q->addr.sin_addr, 4); 331 siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8); 332 #endif 333 memcpy(q->edns.cookie + 16, hash, 8); 334 } 335 336