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 15 #include "dns.h" 16 #include "edns.h" 17 #include "nsd.h" 18 #include "query.h" 19 20 void 21 edns_init_data(edns_data_type *data, uint16_t max_length) 22 { 23 memset(data, 0, sizeof(edns_data_type)); 24 /* record type: OPT */ 25 data->ok[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ 26 data->ok[2] = TYPE_OPT & 0x00ff; /* type_lo */ 27 /* udp payload size */ 28 data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */ 29 data->ok[4] = max_length & 0x00ff; /* size_lo */ 30 31 data->error[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ 32 data->error[2] = TYPE_OPT & 0x00ff; /* type_lo */ 33 data->error[3] = (max_length & 0xff00) >> 8; /* size_hi */ 34 data->error[4] = max_length & 0x00ff; /* size_lo */ 35 data->error[5] = 1; /* XXX Extended RCODE=BAD VERS */ 36 } 37 38 void 39 edns_init_nsid(edns_data_type *data, uint16_t nsid_len) 40 { 41 /* add nsid length bytes */ 42 data->rdata_nsid[0] = ((OPT_HDR + nsid_len) & 0xff00) >> 8; /* length_hi */ 43 data->rdata_nsid[1] = ((OPT_HDR + nsid_len) & 0x00ff); /* length_lo */ 44 45 /* NSID OPT HDR */ 46 data->nsid[0] = (NSID_CODE & 0xff00) >> 8; 47 data->nsid[1] = (NSID_CODE & 0x00ff); 48 data->nsid[2] = (nsid_len & 0xff00) >> 8; 49 data->nsid[3] = (nsid_len & 0x00ff); 50 } 51 52 void 53 edns_init_record(edns_record_type *edns) 54 { 55 edns->status = EDNS_NOT_PRESENT; 56 edns->position = 0; 57 edns->maxlen = 0; 58 edns->opt_reserved_space = 0; 59 edns->dnssec_ok = 0; 60 edns->nsid = 0; 61 edns->ede = -1; /* -1 means no Extended DNS Error */ 62 edns->ede_text = NULL; 63 edns->ede_text_len = 0; 64 } 65 66 /** handle a single edns option in the query */ 67 static int 68 edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, 69 edns_record_type* edns, struct query* query, nsd_type* nsd) 70 { 71 (void) query; /* in case edns options need the query structure */ 72 /* handle opt code and read the optlen bytes from the packet */ 73 switch(optcode) { 74 case NSID_CODE: 75 /* is NSID enabled? */ 76 if(nsd->nsid_len > 0) { 77 edns->nsid = 1; 78 /* we have to check optlen, and move the buffer along */ 79 buffer_skip(packet, optlen); 80 /* in the reply we need space for optcode+optlen+nsid_bytes */ 81 edns->opt_reserved_space += OPT_HDR + nsd->nsid_len; 82 } else { 83 /* ignore option */ 84 buffer_skip(packet, optlen); 85 } 86 break; 87 default: 88 buffer_skip(packet, optlen); 89 break; 90 } 91 return 1; 92 } 93 94 int 95 edns_parse_record(edns_record_type *edns, buffer_type *packet, 96 query_type* query, nsd_type* nsd) 97 { 98 /* OPT record type... */ 99 uint8_t opt_owner; 100 uint16_t opt_type; 101 uint16_t opt_class; 102 uint8_t opt_version; 103 uint16_t opt_flags; 104 uint16_t opt_rdlen; 105 106 edns->position = buffer_position(packet); 107 108 if (!buffer_available(packet, (OPT_LEN + OPT_RDATA))) 109 return 0; 110 111 opt_owner = buffer_read_u8(packet); 112 opt_type = buffer_read_u16(packet); 113 if (opt_owner != 0 || opt_type != TYPE_OPT) { 114 /* Not EDNS. */ 115 buffer_set_position(packet, edns->position); 116 return 0; 117 } 118 119 opt_class = buffer_read_u16(packet); 120 (void)buffer_read_u8(packet); /* opt_extended_rcode */ 121 opt_version = buffer_read_u8(packet); 122 opt_flags = buffer_read_u16(packet); 123 opt_rdlen = buffer_read_u16(packet); 124 125 if (opt_version != 0) { 126 /* The only error is VERSION not implemented */ 127 edns->status = EDNS_ERROR; 128 return 1; 129 } 130 131 if (opt_rdlen > 0) { 132 if(!buffer_available(packet, opt_rdlen)) 133 return 0; 134 if(opt_rdlen > 65530) 135 return 0; 136 /* there is more to come, read opt code */ 137 while(opt_rdlen >= 4) { 138 uint16_t optcode = buffer_read_u16(packet); 139 uint16_t optlen = buffer_read_u16(packet); 140 opt_rdlen -= 4; 141 if(opt_rdlen < optlen) 142 return 0; /* opt too long, formerr */ 143 opt_rdlen -= optlen; 144 if(!edns_handle_option(optcode, optlen, packet, 145 edns, query, nsd)) 146 return 0; 147 } 148 if(opt_rdlen != 0) 149 return 0; 150 } 151 152 edns->status = EDNS_OK; 153 edns->maxlen = opt_class; 154 edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK; 155 return 1; 156 } 157 158 size_t 159 edns_reserved_space(edns_record_type *edns) 160 { 161 /* MIEK; when a pkt is too large?? */ 162 return edns->status == EDNS_NOT_PRESENT ? 0 163 : (OPT_LEN + OPT_RDATA + edns->opt_reserved_space); 164 } 165