/src/freeradius-server/src/protocols/dhcpv6/dhcpv6.h
Line | Count | Source |
1 | | #pragma once |
2 | | /* |
3 | | * This program is free software; you can redistribute it and/or modify |
4 | | * it under the terms of the GNU General Public License as published by |
5 | | * the Free Software Foundation; either version 2 of the License, or |
6 | | * (at your option) any later version. |
7 | | * |
8 | | * This program is distributed in the hope that it will be useful, |
9 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | | * GNU General Public License for more details. |
12 | | * |
13 | | * You should have received a copy of the GNU General Public License |
14 | | * along with this program; if not, write to the Free Software |
15 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
16 | | */ |
17 | | |
18 | | /** |
19 | | * $Id: 0273f1c832021e550123dd15d70ce57aaf948ce8 $ |
20 | | * |
21 | | * @file protocols/dhcpv6/dhcpv6.h |
22 | | * @brief Implementation of the DHCPv6 protocol. |
23 | | * |
24 | | * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org) |
25 | | * |
26 | | * @copyright 2018 The FreeRADIUS server project |
27 | | * @copyright 2018 NetworkRADIUS SARL (legal@networkradius.com) |
28 | | */ |
29 | | RCSIDH(dhcpv6_h, "$Id: 0273f1c832021e550123dd15d70ce57aaf948ce8 $") |
30 | | |
31 | | #include <freeradius-devel/util/dict.h> |
32 | | |
33 | | #include <freeradius-devel/protocol/dhcpv6/dictionary.h> |
34 | | |
35 | 34.7k | #define DHCPV6_MSG_TYPE_LEN 1U |
36 | | |
37 | 26.4k | #define DHCPV6_TRANSACTION_ID_LEN 3U |
38 | | |
39 | 8.29k | #define DHCPV6_HOP_COUNT_LEN 1U |
40 | 8.29k | #define DHCPV6_LINK_ADDRESS_LEN 16U |
41 | 8.29k | #define DHCPV6_PEER_ADDRESS_LEN 16U |
42 | | |
43 | 26.4k | #define DHCPV6_HDR_LEN (DHCPV6_MSG_TYPE_LEN + DHCPV6_TRANSACTION_ID_LEN) |
44 | 8.29k | #define DHCPV6_RELAY_HDR_LEN (DHCPV6_MSG_TYPE_LEN + DHCPV6_HOP_COUNT_LEN + DHCPV6_LINK_ADDRESS_LEN + DHCPV6_PEER_ADDRESS_LEN) |
45 | 187k | #define DHCPV6_OPT_HDR_LEN (sizeof(uint16_t) * 2) |
46 | | |
47 | 87.6k | #define DHCPV6_GET_OPTION_NUM(_x) fr_nbo_to_uint16(_x) |
48 | 150k | #define DHCPV6_GET_OPTION_LEN(_x) fr_nbo_to_uint16((_x) + 2) |
49 | | |
50 | 12.8k | #define DHCPV6_MAX_RELAY_NESTING 10 |
51 | | |
52 | | #define DHCPV6_MAX_ATTRIBUTES 1024 |
53 | | |
54 | | /* |
55 | | * Defined addresses from RFC 8415 Section 7.1 |
56 | | */ |
57 | | #define IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS "FF02::1:2" |
58 | | #define IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_INIT {{{ 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,1,2}}} |
59 | | #define IN6ADDR_ALL_DHCP_SERVERS "FF05::1:3" |
60 | | #define IN6ADDR_ALL_DHCP_SERVERS_INIT {{{ 0xff,0x05,0,0,0,0,0,0,0,0,0,0,0,0,1,3}}} |
61 | | |
62 | | /* |
63 | | * Copied from src/include/protocols/dhcpv6/freeradius.internal.h |
64 | | * and edited. |
65 | | */ |
66 | | typedef enum : uint16_t { |
67 | | FR_DHCPV6_INVALID = 0, |
68 | | FR_DHCPV6_SOLICIT = 1, |
69 | | FR_DHCPV6_ADVERTISE = 2, |
70 | | FR_DHCPV6_REQUEST = 3, |
71 | | FR_DHCPV6_CONFIRM = 4, |
72 | | FR_DHCPV6_RENEW = 5, |
73 | | FR_DHCPV6_REBIND = 6, |
74 | | FR_DHCPV6_REPLY = 7, |
75 | | FR_DHCPV6_RELEASE = 8, |
76 | | FR_DHCPV6_DECLINE = 9, |
77 | | FR_DHCPV6_RECONFIGURE = 10, |
78 | | FR_DHCPV6_INFORMATION_REQUEST = 11, |
79 | | FR_DHCPV6_RELAY_FORWARD = 12, |
80 | | FR_DHCPV6_RELAY_REPLY = 13, |
81 | | FR_DHCPV6_LEASE_QUERY = 14, |
82 | | FR_DHCPV6_LEASE_QUERY_REPLY = 15, |
83 | | FR_DHCPV6_LEASE_QUERY_DONE = 16, |
84 | | FR_DHCPV6_LEASE_QUERY_DATA = 17, |
85 | | FR_DHCPV6_RECONFIGURE_REQUEST = 18, |
86 | | FR_DHCPV6_RECONFIGURE_REPLY = 19, |
87 | | FR_DHCPV6_DHCPV4_QUERY = 20, |
88 | | FR_DHCPV6_DHCPV4_RESPONSE = 21, |
89 | | FR_DHCPV6_ACTIVE_LEASE_QUERY = 22, |
90 | | FR_DHCPV6_START_TLS = 23, |
91 | | FR_DHCPV6_BIND_UPDATE = 24, |
92 | | FR_DHCPV6_BIND_REPLY = 25, |
93 | | FR_DHCPV6_POOL_REQUEST = 26, |
94 | | FR_DHCPV6_POOL_RESPONSE = 27, |
95 | | FR_DHCPV6_UPDATE_REQUEST = 28, |
96 | | FR_DHCPV6_UPDATE_REQUEST_ALL = 29, |
97 | | FR_DHCPV6_UPDATE_DONE = 30, |
98 | | FR_DHCPV6_CONNECT = 31, |
99 | | FR_DHCPV6_CONNECT_REPLY = 32, |
100 | | FR_DHCPV6_DISCONNECT = 33, |
101 | | FR_DHCPV6_STATE = 34, |
102 | | FR_DHCPV6_CONTACT = 35, |
103 | | FR_DHCPV6_CODE_MAX = 36, |
104 | | FR_DHCPV6_DO_NOT_RESPOND = 256 |
105 | | } fr_dhcpv6_packet_code_t; |
106 | | |
107 | | #define FR_DHCPV6_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) < FR_DHCPV6_CODE_MAX)) |
108 | | |
109 | | extern char const *fr_dhcpv6_packet_names[FR_DHCPV6_CODE_MAX]; |
110 | | |
111 | | /** subtype values for DHCPv4 and DHCPv6 |
112 | | * |
113 | | */ |
114 | | typedef struct CC_HINT(__packed__) { |
115 | | uint8_t code; |
116 | | uint8_t transaction_id[3]; |
117 | | } fr_dhcpv6_packet_t; |
118 | | |
119 | | /* |
120 | | * DHCPv6 defines dates to start from Jan 1, 2000. Which is |
121 | | * exactly this number of seconds off of the standard Unix time |
122 | | * stamps. |
123 | | */ |
124 | 0 | #define DHCPV6_DATE_OFFSET (946684800) |
125 | | |
126 | | typedef struct { |
127 | | fr_dict_attr_t const *root; //!< Root attribute of the dictionary. |
128 | | uint8_t const *original; //!< original packet |
129 | | size_t original_length; //!< length of the original packet |
130 | | } fr_dhcpv6_encode_ctx_t; |
131 | | |
132 | | typedef struct { |
133 | | TALLOC_CTX *tmp_ctx; //!< for temporary things cleaned up during decoding |
134 | | uint32_t transaction_id; //!< previous transaction ID |
135 | | uint8_t const *duid; //!< the expected DUID, in wire format |
136 | | size_t duid_len; //!< length of the expected DUID |
137 | | } fr_dhcpv6_decode_ctx_t; |
138 | | |
139 | | typedef struct { |
140 | | bool dns_label; |
141 | | bool partial_dns_label; |
142 | | } fr_dhcpv6_attr_flags_t; |
143 | | |
144 | | extern fr_dict_protocol_t libfreeradius_dhcpv6_dict_protocol; |
145 | | |
146 | | /** Return DHCPv6-specific flags for a given attribute |
147 | | * |
148 | | * Assert in debug builds when the attribute belongs to another dictionary, as |
149 | | * the flags of one protocol say nothing about an attribute of another. |
150 | | * |
151 | | * If the attribute does not carry the protocol-specific extension, then assert. |
152 | | * Other builds log the error and return zeroed flags instead of NULL. |
153 | | */ |
154 | | static inline fr_dhcpv6_attr_flags_t const *fr_dhcpv6_attr_flags(fr_dict_attr_t const *da) |
155 | 10.3k | { |
156 | 10.3k | static fr_dhcpv6_attr_flags_t const no_flags = {}; |
157 | 10.3k | fr_dhcpv6_attr_flags_t const *flags; |
158 | | |
159 | 10.3k | fr_assert_msg(fr_dict_protocol(da->dict) == &libfreeradius_dhcpv6_dict_protocol, |
160 | 10.3k | "%s is not a DHCPv6 attribute, it is from the \"%s\" dictionary", |
161 | 10.3k | da->name, fr_dict_root(da->dict)->name); |
162 | | |
163 | 10.3k | flags = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); |
164 | 10.3k | if (!fr_cond_assert_msg(flags, "%s is not a DHCPv6 attribute, it has no protocol extension", |
165 | 10.3k | da->name)) return &no_flags; |
166 | | |
167 | 10.3k | return flags; |
168 | 10.3k | } base.c:fr_dhcpv6_attr_flags Line | Count | Source | 155 | 3.04k | { | 156 | 3.04k | static fr_dhcpv6_attr_flags_t const no_flags = {}; | 157 | 3.04k | fr_dhcpv6_attr_flags_t const *flags; | 158 | | | 159 | 3.04k | fr_assert_msg(fr_dict_protocol(da->dict) == &libfreeradius_dhcpv6_dict_protocol, | 160 | 3.04k | "%s is not a DHCPv6 attribute, it is from the \"%s\" dictionary", | 161 | 3.04k | da->name, fr_dict_root(da->dict)->name); | 162 | | | 163 | 3.04k | flags = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); | 164 | 3.04k | if (!fr_cond_assert_msg(flags, "%s is not a DHCPv6 attribute, it has no protocol extension", | 165 | 3.04k | da->name)) return &no_flags; | 166 | | | 167 | 3.04k | return flags; | 168 | 3.04k | } |
decode.c:fr_dhcpv6_attr_flags Line | Count | Source | 155 | 7.28k | { | 156 | 7.28k | static fr_dhcpv6_attr_flags_t const no_flags = {}; | 157 | 7.28k | fr_dhcpv6_attr_flags_t const *flags; | 158 | | | 159 | 7.28k | fr_assert_msg(fr_dict_protocol(da->dict) == &libfreeradius_dhcpv6_dict_protocol, | 160 | 7.28k | "%s is not a DHCPv6 attribute, it is from the \"%s\" dictionary", | 161 | 7.28k | da->name, fr_dict_root(da->dict)->name); | 162 | | | 163 | 7.28k | flags = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); | 164 | 7.28k | if (!fr_cond_assert_msg(flags, "%s is not a DHCPv6 attribute, it has no protocol extension", | 165 | 7.28k | da->name)) return &no_flags; | 166 | | | 167 | 7.28k | return flags; | 168 | 7.28k | } |
|
169 | | |
170 | | static inline bool fr_dhcpv6_flag_dns_label(fr_dict_attr_t const *da) |
171 | 0 | { |
172 | 0 | return fr_dhcpv6_attr_flags(da)->dns_label; |
173 | 0 | } Unexecuted instantiation: base.c:fr_dhcpv6_flag_dns_label Unexecuted instantiation: decode.c:fr_dhcpv6_flag_dns_label Unexecuted instantiation: encode.c:fr_dhcpv6_flag_dns_label |
174 | | |
175 | | static inline bool fr_dhcpv6_flag_partial_dns_label(fr_dict_attr_t const *da) |
176 | 0 | { |
177 | 0 | return fr_dhcpv6_attr_flags(da)->partial_dns_label; |
178 | 0 | } Unexecuted instantiation: base.c:fr_dhcpv6_flag_partial_dns_label Unexecuted instantiation: decode.c:fr_dhcpv6_flag_partial_dns_label Unexecuted instantiation: encode.c:fr_dhcpv6_flag_partial_dns_label |
179 | | |
180 | | static inline bool fr_dhcpv6_flag_any_dns_label(fr_dict_attr_t const *da) |
181 | 10.3k | { |
182 | 10.3k | fr_dhcpv6_attr_flags_t const *flags = fr_dhcpv6_attr_flags(da); |
183 | | |
184 | 10.3k | return flags->dns_label || flags->partial_dns_label; |
185 | 10.3k | } base.c:fr_dhcpv6_flag_any_dns_label Line | Count | Source | 181 | 3.04k | { | 182 | 3.04k | fr_dhcpv6_attr_flags_t const *flags = fr_dhcpv6_attr_flags(da); | 183 | | | 184 | 3.04k | return flags->dns_label || flags->partial_dns_label; | 185 | 3.04k | } |
decode.c:fr_dhcpv6_flag_any_dns_label Line | Count | Source | 181 | 7.28k | { | 182 | 7.28k | fr_dhcpv6_attr_flags_t const *flags = fr_dhcpv6_attr_flags(da); | 183 | | | 184 | 7.28k | return flags->dns_label || flags->partial_dns_label; | 185 | 7.28k | } |
Unexecuted instantiation: encode.c:fr_dhcpv6_flag_any_dns_label |
186 | | |
187 | | /* |
188 | | * base.c |
189 | | */ |
190 | | uint8_t const *fr_dhcpv6_option_find(uint8_t const *start, uint8_t const *end, unsigned int option); |
191 | | |
192 | | bool fr_dhcpv6_ok(uint8_t const *packet, size_t packet_len, |
193 | | uint32_t max_attributes); |
194 | | |
195 | | bool fr_dhcpv6_verify(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx, |
196 | | bool from_server); |
197 | | |
198 | | ssize_t fr_dhcpv6_encode(fr_dbuff_t *dbuff, uint8_t const *original, size_t length, |
199 | | int msg_type, fr_pair_list_t *vps); |
200 | | |
201 | | ssize_t fr_dhcpv6_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *packet, size_t packet_len); |
202 | | |
203 | | void fr_dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len); |
204 | | |
205 | | int fr_dhcpv6_global_init(void); |
206 | | |
207 | | void fr_dhcpv6_global_free(void); |
208 | | |
209 | | /* |
210 | | * encode.c |
211 | | */ |
212 | | void *fr_dhcpv6_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx); |
213 | | |
214 | | ssize_t fr_dhcpv6_encode_option(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void * encode_ctx); |
215 | | |
216 | | ssize_t fr_dhcpv6_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list); |
217 | | |
218 | | /* |
219 | | * decode.c |
220 | | */ |
221 | | ssize_t fr_dhcpv6_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, |
222 | | uint8_t const *data, size_t data_len, void *decode_ctx); |
223 | | |
224 | | ssize_t fr_dhcpv6_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, |
225 | | uint8_t const *data, size_t data_len); |