28 #include <freeradius-devel/io/pair.h>
29 #include <freeradius-devel/protocol/dhcpv6/freeradius.internal.h>
30 #include <freeradius-devel/protocol/dhcpv6/rfc3315.h>
31 #include <freeradius-devel/protocol/dhcpv6/rfc5007.h>
32 #include <freeradius-devel/util/proto.h>
33 #include <freeradius-devel/util/rand.h>
73 [FR_PACKET_TYPE_VALUE_SOLICIT] =
"Solicit",
74 [FR_PACKET_TYPE_VALUE_ADVERTISE] =
"Advertise",
75 [FR_PACKET_TYPE_VALUE_REQUEST] =
"Request",
76 [FR_PACKET_TYPE_VALUE_CONFIRM] =
"Confirm",
77 [FR_PACKET_TYPE_VALUE_RENEW] =
"Renew",
78 [FR_PACKET_TYPE_VALUE_REBIND] =
"Rebind",
79 [FR_PACKET_TYPE_VALUE_REPLY] =
"Reply",
80 [FR_PACKET_TYPE_VALUE_RELEASE] =
"Release",
81 [FR_PACKET_TYPE_VALUE_DECLINE] =
"Decline",
82 [FR_PACKET_TYPE_VALUE_RECONFIGURE] =
"Reconfigure",
83 [FR_PACKET_TYPE_VALUE_INFORMATION_REQUEST] =
"Information-Request",
84 [FR_PACKET_TYPE_VALUE_RELAY_FORWARD] =
"Relay-Forward",
85 [FR_PACKET_TYPE_VALUE_RELAY_REPLY] =
"Relay-Reply",
86 [FR_PACKET_TYPE_VALUE_LEASE_QUERY] =
"Lease-Query",
87 [FR_PACKET_TYPE_VALUE_LEASE_QUERY_REPLY] =
"Lease-Query-Reply",
88 [FR_PACKET_TYPE_VALUE_LEASE_QUERY_DONE] =
"Lease-Query-Done",
89 [FR_PACKET_TYPE_VALUE_LEASE_QUERY_DATA] =
"Lease-Query-Data",
90 [FR_PACKET_TYPE_VALUE_RECONFIGURE_REQUEST] =
"Reconfigure-Request",
91 [FR_PACKET_TYPE_VALUE_RECONFIGURE_REPLY] =
"Reconfigure-Reply",
92 [FR_PACKET_TYPE_VALUE_DHCPV4_QUERY] =
"DHCPv4-Query",
93 [FR_PACKET_TYPE_VALUE_DHCPV4_RESPONSE] =
"DHCPv4-Response",
94 [FR_PACKET_TYPE_VALUE_ACTIVE_LEASE_QUERY] =
"Active-Lease-Query",
95 [FR_PACKET_TYPE_VALUE_START_TLS] =
"Start-TLS",
96 [FR_PACKET_TYPE_VALUE_BIND_UPDATE] =
"Bind-Update",
97 [FR_PACKET_TYPE_VALUE_BIND_REPLY] =
"Bind-Reply",
98 [FR_PACKET_TYPE_VALUE_POOL_REQUEST] =
"Pool-Request",
99 [FR_PACKET_TYPE_VALUE_POOL_RESPONSE] =
"Pool-Response",
100 [FR_PACKET_TYPE_VALUE_UPDATE_REQUEST] =
"Update-Request",
101 [FR_PACKET_TYPE_VALUE_UPDATE_REQUEST_ALL] =
"Update-Request-All",
102 [FR_PACKET_TYPE_VALUE_UPDATE_DONE] =
"Update-Done",
103 [FR_PACKET_TYPE_VALUE_CONNECT] =
"Connect",
104 [FR_PACKET_TYPE_VALUE_CONNECT_REPLY] =
"Connect-Reply",
105 [FR_PACKET_TYPE_VALUE_DISCONNECT] =
"Disconnect",
106 [FR_PACKET_TYPE_VALUE_STATE] =
"State",
107 [FR_PACKET_TYPE_VALUE_CONTACT] =
"Contact"
114 {
L(
"dns_label"), { .func = dict_flag_dns_label } },
115 {
L(
"partial_dns_label"), { .func = dict_flag_partial_dns_label } }
121 bool allow_relay,
int depth)
134 return -(p - packet);
140 return -(p - packet);
144 if (attributes > (
size_t) max_attributes) {
146 return -(p - packet);
160 if (child <= 0)
return -((p + 4) - packet) + child;
176 size_t packet_len = end - packet;
215 if (attributes < 0)
return -(p - packet) + attributes;
261 if (found == option)
return p;
274 if (len != packet_ctx->
duid_len)
return false;
275 if (memcmp(option + 4, packet_ctx->
duid, packet_ctx->
duid_len) != 0)
return false;
287 uint8_t const *options = packet + 4;
288 uint8_t const *end = packet + packet_len;
291 case FR_PACKET_TYPE_VALUE_ADVERTISE:
315 if (!packet_ctx->
duid) {
329 case FR_PACKET_TYPE_VALUE_REPLY:
340 if (!packet_ctx->
duid)
return true;
345 case FR_PACKET_TYPE_VALUE_RECONFIGURE:
349 if (!option)
goto fail_cid;
354 if (!packet_ctx->
duid)
goto fail_duid;
355 if (!
duid_match(option, packet_ctx))
goto fail_match;
395 if (!option)
goto fail_cid;
400 if (!packet_ctx->
duid)
goto fail_duid;
401 if (!
duid_match(option, packet_ctx))
goto fail_match;
404 case FR_PACKET_TYPE_VALUE_REQUEST:
405 case FR_PACKET_TYPE_VALUE_CONFIRM:
406 case FR_PACKET_TYPE_VALUE_RENEW:
407 case FR_PACKET_TYPE_VALUE_REBIND:
408 case FR_PACKET_TYPE_VALUE_RELEASE:
409 case FR_PACKET_TYPE_VALUE_DECLINE:
410 case FR_PACKET_TYPE_VALUE_INFORMATION_REQUEST:
426 uint8_t const *options = packet + 4;
427 uint8_t const *end = packet + packet_len;
432 if (!packet_ctx->
duid) {
438 case FR_PACKET_TYPE_VALUE_SOLICIT:
439 case FR_PACKET_TYPE_VALUE_CONFIRM:
440 case FR_PACKET_TYPE_VALUE_REBIND:
454 case FR_PACKET_TYPE_VALUE_REQUEST:
455 case FR_PACKET_TYPE_VALUE_RENEW:
456 case FR_PACKET_TYPE_VALUE_DECLINE:
457 case FR_PACKET_TYPE_VALUE_RELEASE:
461 if (!option)
goto fail_sid;
470 case FR_PACKET_TYPE_VALUE_INFORMATION_REQUEST:
472 if (!option)
goto fail_sid;
474 if (!
duid_match(option, packet_ctx))
goto fail_match;
508 case FR_PACKET_TYPE_VALUE_LEASE_QUERY:
516 if (option && !
duid_match(option, packet_ctx))
goto fail_match;
525 case FR_PACKET_TYPE_VALUE_ADVERTISE:
526 case FR_PACKET_TYPE_VALUE_REPLY:
527 case FR_PACKET_TYPE_VALUE_RECONFIGURE:
555 if ((packet[0] == 0) || (packet[0] > FR_PACKET_TYPE_VALUE_RELAY_REPLY))
return false;
557 if (!packet_ctx->
duid)
return false;
598 vp->vp_uint32 = packet[0];
664 end = packet + packet_len;
687 talloc_free_children(packet_ctx.
tmp_ctx);
708 if (c->
da->dict !=
dict || c->
da->flags.internal)
continue;
709 if (c->vp_type ==
FR_TYPE_BOOL && !c->vp_bool)
continue;
733 if (
vp) msg_type =
vp->vp_uint32;
736 if ((msg_type <= 0) || (msg_type >
UINT8_MAX)) {
747 if (likely(
vp != NULL)) {
754 if (likely(
vp != NULL)) {
761 if (likely(
vp != NULL)) {
786 packet_ctx.
root = root;
800 static char const tabs[] =
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
806 for (i = 0; i < attrlen; i++) {
807 if ((i > 0) && ((i & 0x0f) == 0x00))
809 fprintf(fp,
"%02x ", ptr[i]);
810 if ((i & 0x0f) == 0x0f) fprintf(fp,
"\n");
812 if ((i & 0x0f) != 0) fprintf(fp,
"\n");
817 uint8_t const *option, *end = packet + packet_len;
819 if (packet_len < 4) {
821 fprintf(fp,
"???:\t");
830 fprintf(fp,
"packet: %02x\n", packet[0]);
833 if ((packet[0] == FR_PACKET_TYPE_VALUE_RELAY_FORWARD) ||
834 (packet[0] == FR_PACKET_TYPE_VALUE_RELAY_REPLY)) {
835 if (packet_len < 34) {
837 fprintf(fp,
"???:\t");
843 fprintf(fp,
"hops: %02x\n", packet[1]);
845 fprintf(fp,
"relay link address: ");
849 fprintf(fp,
"peer address: ");
851 option = packet + 34;
854 fprintf(fp,
"transaction id: ");
860 fprintf(fp,
"options\n");
861 while (option < end) {
864 if ((end - option) < 4) {
866 fprintf(fp,
"???:\t");
875 if (length > end - (option + 4)) {
885 option += 4 + length;
927 if (child->flags.internal)
continue;
929 value.vb_uint16 = child->attr;
932 child->name, &
value,
true,
false) < 0) {
957 da->flags.is_known_width =
true;
974 if (da->flags.extra || !da->flags.subtype)
return true;
977 fr_strerror_const(
"The 'dns_label' flag can only be used with attributes of type 'string'");
981 da->flags.is_known_width =
true;
989 .default_type_size = 2,
990 .default_type_length = 2,
#define L(_str)
Helper for initialising arrays of string literals.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
fr_dcursor_eval_t void const * uctx
fr_dcursor_iter_t void * current
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Implementation of the DHCPv6 protocol.
uint32_t transaction_id
previous transaction ID
@ FR_DHCPV6_RELAY_FORWARD
@ FR_DHCPV6_LEASE_QUERY_REPLY
fr_dict_attr_t const * root
Root attribute of the dictionary.
#define DHCPV6_GET_OPTION_NUM(_x)
uint8_t * duid
the expected DUID, in wire format
#define DHCPV6_RELAY_HDR_LEN
#define DHCPV6_LINK_ADDRESS_LEN
#define DHCPV6_PEER_ADDRESS_LEN
#define DHCPV6_GET_OPTION_LEN(_x)
static bool fr_dhcpv6_flag_any_dns_label(fr_dict_attr_t const *da)
uint8_t const * original
original packet
ssize_t fr_dhcpv6_encode_option(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a DHCPv6 option and any sub-options.
#define DHCPV6_OPT_HDR_LEN
#define DHCPV6_TRANSACTION_ID_LEN
size_t original_length
length of the original packet
#define DHCPV6_HOP_COUNT_LEN
size_t duid_len
length of the expected DUID
#define DHCPV6_MAX_RELAY_NESTING
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
ssize_t fr_dhcpv6_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool replace)
Add a value name.
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
#define fr_dict_autofree(_to_free)
fr_dict_attr_t const * fr_dict_attr_iterate_children(fr_dict_attr_t const *parent, fr_dict_attr_t const **prev)
Iterate over children of a DA.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
#define fr_dict_autoload(_to_load)
char const * name
name of this protocol
#define FR_DICT_ATTR_FLAG_FUNC(_struct, _name)
Define a flag setting function, which sets one bit in a fr_dict_attr_flags_t.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
Protocol specific custom flag definitnion.
Protocol-specific callbacks in libfreeradius-PROTOCOL.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Head of a doubly linked list.
fr_dict_attr_t const * attr_packet_type
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
static uint8_t depth(fr_minmax_heap_index_t i)
static void fr_nbo_from_uint24(uint8_t out[static 3], uint32_t num)
Write out an unsigned 24bit integer in wire format (big endian)
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
static uint32_t fr_nbo_to_uint24(uint8_t const data[static 3])
Read an unsigned 24bit integer from wire format (big endian)
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
fr_dict_attr_t const * attr_option_request
fr_dict_autoload_t libfreeradius_dhcpv6_dict[]
uint8_t const * fr_dhcpv6_option_find(uint8_t const *start, uint8_t const *end, unsigned int option)
fr_dict_attr_t const * attr_hop_count
fr_dict_attr_t const * attr_relay_link_address
static bool duid_match(uint8_t const *option, fr_dhcpv6_decode_ctx_t const *packet_ctx)
void fr_dhcpv6_global_free(void)
fr_dict_protocol_t libfreeradius_dhcpv6_dict_protocol
static void print_hex_data(FILE *fp, uint8_t const *ptr, int attrlen, int depth)
static ssize_t fr_dhcpv6_ok_internal(uint8_t const *packet, uint8_t const *end, size_t max_attributes, int depth)
static uint32_t instance_count
static void dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len, int depth)
bool fr_dhcpv6_ok(uint8_t const *packet, size_t packet_len, uint32_t max_attributes)
See if the data pointed to by PTR is a valid DHCPv6 packet.
static bool attr_valid(fr_dict_attr_t *da)
int fr_dhcpv6_global_init(void)
static ssize_t fr_dhcpv6_options_ok(uint8_t const *packet, uint8_t const *end, size_t max_attributes, bool allow_relay, int depth)
ssize_t fr_dhcpv6_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *packet, size_t packet_len)
Decode a DHCPv6 packet.
char const * fr_dhcpv6_packet_names[FR_DHCPV6_CODE_MAX]
fr_dict_attr_t const * attr_relay_message
fr_dict_attr_autoload_t libfreeradius_dhcpv6_dict_attr[]
static fr_dict_flag_parser_t const dhcpv6_flags[]
fr_dict_t const * dict_dhcpv6
fr_dict_attr_t const * attr_transaction_id
void * fr_dhcpv6_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
DHCPV6-specific iterator.
bool fr_dhcpv6_verify(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx, bool from_server)
Verify the packet under some various circumstances.
static bool verify_to_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx)
Verify a reply packet from a server to a client.
static bool verify_from_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx)
Verify a packet from a client to a server.
void fr_dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
Print a raw DHCP packet as hex.
fr_dict_attr_t const * attr_relay_peer_address
ssize_t fr_dhcpv6_encode(fr_dbuff_t *dbuff, uint8_t const *original, size_t length, int msg_type, fr_pair_list_t *vps)
Encode a DHCPv6 packet.
ssize_t fr_dhcpv6_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *decode_ctx)
Create a "normal" fr_pair_t from the given data.
ssize_t fr_dhcpv6_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
uint32_t fr_rand(void)
Return a 32-bit random number.
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
return fr_dbuff_set(dbuff, &our_dbuff)
#define fr_box_uint16(_val)
#define FR_VALUE_BOX_TO_NETWORK_RETURN(_dbuff, _value)
static size_t char ** out