1 /*
2 * Copyright (c) 2011 NLNet Labs. All rights reserved.
3 *
4 * Taken from NSD3 and adjusted for OpenDNSSEC, NLnet Labs.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 /**
30 * TSIG.
31 *
32 */
33
34 #include "config.h"
35 #include "compat.h"
36
37 #include "wire/buffer.h"
38 #include "wire/edns.h"
39
40 #include <ldns/ldns.h>
41
42 static const char* edns_str = "edns";
43
44
45 /**
46 * Create new EDNS RR.
47 *
48 */
49 edns_rr_type*
edns_rr_create()50 edns_rr_create()
51 {
52 edns_rr_type* err = NULL;
53 CHECKALLOC(err = (edns_rr_type*) malloc(sizeof(edns_rr_type))) ;
54 edns_rr_reset(err);
55 return err;
56 }
57
58
59 /**
60 * Initialize EDNS.
61 *
62 */
63 void
edns_init(edns_data_type * data,uint16_t max_length)64 edns_init(edns_data_type* data, uint16_t max_length)
65 {
66 if (!data) {
67 return;
68 }
69 memset(data, 0, sizeof(edns_data_type));
70 /* record type: OPT */
71 data->ok[1] = (LDNS_RR_TYPE_OPT & 0xff00) >> 8; /* type_hi */
72 data->ok[2] = LDNS_RR_TYPE_OPT & 0x00ff; /* type_lo */
73 /* udp payload size */
74 data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */
75 data->ok[4] = max_length & 0x00ff; /* size_lo */
76
77 data->error[1] = (LDNS_RR_TYPE_OPT & 0xff00) >> 8; /* type_hi */
78 data->error[2] = LDNS_RR_TYPE_OPT & 0x00ff; /* type_lo */
79 data->error[3] = (max_length & 0xff00) >> 8; /* size_hi */
80 data->error[4] = max_length & 0x00ff; /* size_lo */
81 data->error[5] = 1; /* Extended RCODE=BAD VERS */
82 }
83
84
85 /**
86 * Reset EDNS OPT RR.
87 *
88 */
89 void
edns_rr_reset(edns_rr_type * err)90 edns_rr_reset(edns_rr_type* err)
91 {
92 if (!err) {
93 return;
94 }
95 err->status = EDNS_NOT_PRESENT;
96 err->position = 0;
97 err->maxlen = 0;
98 err->dnssec_ok = 0;
99 }
100
101
102 /**
103 * Parse EDNS OPT RR.
104 *
105 */
106 int
edns_rr_parse(edns_rr_type * err,buffer_type * buffer)107 edns_rr_parse(edns_rr_type* err, buffer_type* buffer)
108 {
109 /* OPT record type... */
110 uint8_t opt_owner;
111 uint16_t opt_type;
112 uint16_t opt_class;
113 uint8_t opt_version;
114 uint16_t opt_flags;
115 uint16_t opt_rdlen;
116
117 if (!err || !buffer) {
118 ods_log_debug("[%s] parse: no edns rr or no packet buffer available",
119 edns_str);
120 return 0;
121 }
122
123 err->position = buffer_position(buffer);
124 if (!buffer_available(buffer, (OPT_LEN + OPT_RDATA))) {
125 ods_log_debug("[%s] parse: edns rr too small", edns_str);
126 return 0;
127 }
128 opt_owner = buffer_read_u8(buffer);
129 opt_type = buffer_read_u16(buffer);
130 if (opt_owner != 0 || opt_type != LDNS_RR_TYPE_OPT) {
131 /* Not EDNS. */
132 ods_log_debug("[%s] parse: not OPT: owner=%02x, type=%02x", edns_str,
133 opt_owner, opt_type);
134 buffer_set_position(buffer, err->position);
135 return 0;
136 }
137 opt_class = buffer_read_u16(buffer);
138 (void)buffer_read_u8(buffer); /* opt_extended_rcode */
139 opt_version = buffer_read_u8(buffer);
140 opt_flags = buffer_read_u16(buffer);
141 opt_rdlen = buffer_read_u16(buffer);
142 buffer_skip(buffer, opt_rdlen);
143
144 if (opt_version != 0) {
145 /* The only error is VERSION not implemented */
146 ods_log_debug("[%s] parse: wrong edns version", edns_str);
147 err->status = EDNS_ERROR;
148 return 1;
149 }
150 err->status = EDNS_OK;
151 err->maxlen = opt_class;
152 err->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
153 return 1;
154 }
155
156
157 /**
158 * The amount of space to reserve in the response for the EDNS data.
159 *
160 */
161 size_t
edns_rr_reserved_space(edns_rr_type * err)162 edns_rr_reserved_space(edns_rr_type* err)
163 {
164 if (!err) {
165 return 0;
166 }
167 return err->status == EDNS_NOT_PRESENT ? 0 : (OPT_LEN + OPT_RDATA);
168 }
169
170
171 void
edns_rr_cleanup(edns_rr_type * err)172 edns_rr_cleanup(edns_rr_type* err)
173 {
174 if (!err)
175 return;
176 free(err);
177 }
178