The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
encode.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 6c8153134cf5e2601198614054bf338b729e2a93 $
19  *
20  * @file protocols/bfd/encode.c
21  * @brief Functions to encode BFD packets
22  *
23  * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
24  */
25 RCSID("$Id: 6c8153134cf5e2601198614054bf338b729e2a93 $")
26 
27 #include <freeradius-devel/util/dbuff.h>
28 #include <freeradius-devel/util/struct.h>
29 #include <freeradius-devel/io/test_point.h>
30 #include <freeradius-devel/internal/internal.h>
31 
32 #include "attrs.h"
33 
34 /** Encodes the data portion of an attribute
35  *
36  * @return
37  * > 0, Length of the data portion.
38  * = 0, we could not encode anything, skip this attribute (and don't encode the header)
39  * unless it's one of a list of exceptions.
40  * < 0, How many additional bytes we'd need as a negative integer.
41  * PAIR_ENCODE_FATAL_ERROR - Abort encoding the packet.
42  */
44  fr_da_stack_t *da_stack, unsigned int depth,
45  fr_dcursor_t *cursor, void *encode_ctx)
46 {
47  ssize_t slen;
48  fr_pair_t const *vp = fr_dcursor_current(cursor);
49  fr_dict_attr_t const *da = da_stack->da[depth];
50 // fr_bfd_ctx_t *packet_ctx = encode_ctx;
51  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
52 
53  PAIR_VERIFY(vp);
54  FR_PROTO_STACK_PRINT(da_stack, depth);
55 
56  /*
57  * This has special requirements.
58  */
59  if ((vp->vp_type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_STRUCT)) {
60  slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, NULL);
61  goto done;
62  }
63 
64  /*
65  * If it's not a TLV, it should be a value type RFC
66  * attribute make sure that it is.
67  */
68  if (da_stack->da[depth + 1] != NULL) {
69  fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
71  }
72 
73  if (vp->da != da) {
74  fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
76  }
77 
78  if (fr_type_is_structural(da->type)) {
79  fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
80  fr_type_to_str(da_stack->da[depth]->type));
82  }
83 
84  slen = fr_value_box_to_network(&work_dbuff, &vp->data);
85 
86 done:
87  if (slen < 0) return slen;
88 
89  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "%pP", vp);
90 
91  vp = fr_dcursor_next(cursor);
92  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
93 
94  return fr_dbuff_set(dbuff, &work_dbuff);
95 }
96 
97 /** Encode VPS into a BFD packet.
98  *
99  */
100 ssize_t fr_bfd_encode(uint8_t *out, size_t outlen, UNUSED uint8_t const *original,
101  char const *secret, size_t secret_len, fr_pair_list_t *vps)
102 {
103  ssize_t slen;
104  fr_bfd_ctx_t packet_ctx;
105  bfd_packet_t *packet;
106  fr_dcursor_t cursor;
107  fr_dbuff_t work_dbuff = FR_DBUFF_TMP(out, outlen);
108  fr_da_stack_t da_stack;
109 
111  fr_strerror_const("No BFD attributes found in the list");
112  return -1;
113  }
114 
115  packet_ctx.secret = secret;
116 
118  FR_PROTO_STACK_PRINT(&da_stack, 0);
119 
120  slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &cursor, &packet_ctx, encode_value, NULL);
121  if (slen < 0) return slen;
122 
123  /*
124  * The length is only 8 bits. :(
125  */
126  if (slen > UINT8_MAX) {
127  fr_strerror_const("Packet is larger than 255 octets");
128  return -1;
129  }
130 
131  /*
132  * For various reasons the base BFD struct has "auth-type" as the last MEMBER, even if it's not
133  * always used. The struct encoder will fill it in with zeros, so we have to check for
134  * "auth_present" and then remove the last byte if there's no authentication stuff present.
135  */
136  packet = (bfd_packet_t *) out;
137 
138  if (!packet->auth_present) {
139  if (slen > FR_BFD_HEADER_LENGTH) slen = FR_BFD_HEADER_LENGTH;
140 
141  } else if (!secret || secret_len == 0) {
142  fr_strerror_const("Cannot sign packets without a secret");
143  return -1;
144 
145  } else {
146 
147 #if 0
148  /*
149  * @todo - sign the packet with the chosen auth type
150  */
151  if (fr_bfd_sign(data, NULL, (uint8_t const *) secret, secret_len - 1) < 0) {
152  return -1;
153  }
154 #endif
155  }
156 
157  packet->length = slen;
158 
159  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), slen, "BFD Packet");
160 
161  return slen;
162 }
163 
164 
165 static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
166 {
167  fr_bfd_ctx_t *test_ctx;
168 
169  test_ctx = talloc_zero(ctx, fr_bfd_ctx_t);
170  if (!test_ctx) return -1;
171 
172  test_ctx->secret = talloc_strdup(test_ctx, "testing123");
173 
174  *out = test_ctx;
175 
176  return 0;
177 }
178 
179 static ssize_t fr_bfd_encode_proto(UNUSED TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, void *proto_ctx)
180 {
181  fr_bfd_ctx_t *test_ctx = talloc_get_type_abort(proto_ctx, fr_bfd_ctx_t);
182  ssize_t slen, alen;
183  fr_pair_t *vp;
184  fr_dbuff_t dbuff;
185 
186  /*
187  * @todo - pass in test_ctx to this function, so that we
188  * can leverage a consistent random number generator.
189  */
190  slen = fr_bfd_encode(data, data_len, NULL, test_ctx->secret, talloc_array_length(test_ctx->secret) - 1, vps);
191  if (slen <= 0) return slen;
192 
194  if (!vp) return slen;
195 
196  fr_dbuff_init(&dbuff, data + slen, data_len - slen);
197  alen = fr_internal_encode_list(&dbuff, &vp->vp_group, NULL);
198  if (alen <= 0) return slen;
199 
200  return slen + alen;
201 }
202 
203 /*
204  * No one else should be using this.
205  */
206 extern void *fr_bfd_next_encodable(fr_dlist_head_t *list, void *to_eval, void *uctx);
207 
208 /*
209  * Test points
210  */
214  .func = fr_bfd_encode_proto
215 };
#define FR_BFD_HEADER_LENGTH
Definition: bfd.h:141
char const * secret
shared secret. MUST be talloc'd
Definition: bfd.h:156
#define RCSID(id)
Definition: build.h:481
#define UNUSED
Definition: build.h:313
#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...
Definition: dbuff.h:767
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition: dbuff.h:354
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:898
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:514
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:288
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:337
Head of a doubly linked list.
Definition: dlist.h:51
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
Definition: pair.h:36
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define UINT8_MAX
Definition: merged_model.c:32
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
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.
Definition: pair.c:693
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
Definition: proto.c:118
static fr_dict_attr_t const * attr_bfd_packet
Definition: proto_bfd.c:69
static fr_internal_encode_ctx_t encode_ctx
HIDDEN fr_dict_attr_t const * attr_bfd_additional_data
Definition: base.c:52
static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encodes the data portion of an attribute.
Definition: encode.c:43
fr_test_point_proto_encode_t bfd_tp_encode_proto
Definition: encode.c:212
void * fr_bfd_next_encodable(fr_dlist_head_t *list, void *to_eval, void *uctx)
static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
Definition: encode.c:165
static ssize_t fr_bfd_encode_proto(UNUSED TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, void *proto_ctx)
Definition: encode.c:179
ssize_t fr_bfd_encode(uint8_t *out, size_t outlen, UNUSED uint8_t const *original, char const *secret, size_t secret_len, fr_pair_list_t *vps)
Encode VPS into a BFD packet.
Definition: encode.c:100
ssize_t fr_internal_encode_list(fr_dbuff_t *dbuff, fr_pair_list_t const *list, void *encode_ctx)
Encode a list of pairs using the internal encoder.
Definition: encode.c:303
VQP attributes.
static char * secret
Definition: radclient-ng.c:69
static bool done
Definition: radclient.c:80
fr_pair_t * vp
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *parent_cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
Definition: struct.c:470
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:94
Entry point for protocol encoders.
Definition: test_point.h:93
#define PAIR_VERIFY(_x)
Definition: pair.h:191
#define fr_pair_dcursor_by_ancestor_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
Definition: pair.h:646
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition: proto.h:41
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition: proto.h:43
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition: proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition: proto.h:54
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_structural(_x)
Definition: types.h:371
return fr_dbuff_set(dbuff, &our_dbuff)
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition: value.c:1404
static fr_slen_t data
Definition: value.h:1265
static size_t char ** out
Definition: value.h:997