Coverage Report

Created: 2026-10-18 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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);