xref: /openbsd/usr.sbin/nsd/edns.c (revision cecf84d4)
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 
18 void
19 edns_init_data(edns_data_type *data, uint16_t max_length)
20 {
21 	memset(data, 0, sizeof(edns_data_type));
22 	/* record type: OPT */
23 	data->ok[1] = (TYPE_OPT & 0xff00) >> 8;	/* type_hi */
24 	data->ok[2] = TYPE_OPT & 0x00ff;	/* type_lo */
25 	/* udp payload size */
26 	data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */
27 	data->ok[4] = max_length & 0x00ff;	  /* size_lo */
28 
29 	data->error[1] = (TYPE_OPT & 0xff00) >> 8;	/* type_hi */
30 	data->error[2] = TYPE_OPT & 0x00ff;		/* type_lo */
31 	data->error[3] = (max_length & 0xff00) >> 8;	/* size_hi */
32 	data->error[4] = max_length & 0x00ff;		/* size_lo */
33 	data->error[5] = 1;	/* XXX Extended RCODE=BAD VERS */
34 }
35 
36 void
37 edns_init_nsid(edns_data_type *data, uint16_t nsid_len)
38 {
39        /* add nsid length bytes */
40        data->rdata_nsid[0] = ((OPT_HDR + nsid_len) & 0xff00) >> 8; /* length_hi */
41        data->rdata_nsid[1] = ((OPT_HDR + nsid_len) & 0x00ff);      /* length_lo */
42 
43        /* NSID OPT HDR */
44        data->nsid[0] = (NSID_CODE & 0xff00) >> 8;
45        data->nsid[1] = (NSID_CODE & 0x00ff);
46        data->nsid[2] = (nsid_len & 0xff00) >> 8;
47        data->nsid[3] = (nsid_len & 0x00ff);
48 }
49 
50 void
51 edns_init_record(edns_record_type *edns)
52 {
53 	edns->status = EDNS_NOT_PRESENT;
54 	edns->position = 0;
55 	edns->maxlen = 0;
56 	edns->dnssec_ok = 0;
57 	edns->nsid = 0;
58 }
59 
60 int
61 edns_parse_record(edns_record_type *edns, buffer_type *packet)
62 {
63 	/* OPT record type... */
64 	uint8_t  opt_owner;
65 	uint16_t opt_type;
66 	uint16_t opt_class;
67 	uint8_t  opt_version;
68 	uint16_t opt_flags;
69 	uint16_t opt_rdlen;
70 	uint16_t opt_nsid;
71 
72 	edns->position = buffer_position(packet);
73 
74 	if (!buffer_available(packet, (OPT_LEN + OPT_RDATA)))
75 		return 0;
76 
77 	opt_owner = buffer_read_u8(packet);
78 	opt_type = buffer_read_u16(packet);
79 	if (opt_owner != 0 || opt_type != TYPE_OPT) {
80 		/* Not EDNS.  */
81 		buffer_set_position(packet, edns->position);
82 		return 0;
83 	}
84 
85 	opt_class = buffer_read_u16(packet);
86 	(void)buffer_read_u8(packet); /* opt_extended_rcode */
87 	opt_version = buffer_read_u8(packet);
88 	opt_flags = buffer_read_u16(packet);
89 	opt_rdlen = buffer_read_u16(packet);
90 
91 	if (opt_version != 0) {
92 		/* The only error is VERSION not implemented */
93 		edns->status = EDNS_ERROR;
94 		return 1;
95 	}
96 
97 	if (opt_rdlen > 0) {
98 		/* there is more to come, read opt code
99 		 * should be NSID - there are no others */
100 		opt_nsid = buffer_read_u16(packet);
101 		edns->nsid = (opt_nsid == NSID_CODE);
102 		/* extra check for the value */
103 	}
104 
105 	edns->status = EDNS_OK;
106 	edns->maxlen = opt_class;
107 	edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
108 	return 1;
109 }
110 
111 size_t
112 edns_reserved_space(edns_record_type *edns)
113 {
114 	/* MIEK; when a pkt is too large?? */
115 	return edns->status == EDNS_NOT_PRESENT ? 0 : (OPT_LEN + OPT_RDATA);
116 }
117