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