Coverage Report

Created: 2026-01-17 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/protocols/bfd/decode.c
Line
Count
Source
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: 869c0953c554275994f1280f97aea874a7e08eae $
19
 *
20
 * @file protocols/bfd/decode.c
21
 * @brief Functions to decode BFD packets
22
 *
23
 * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
24
 */
25
RCSID("$Id: 869c0953c554275994f1280f97aea874a7e08eae $")
26
27
#include <freeradius-devel/util/struct.h>
28
#include <freeradius-devel/io/test_point.h>
29
#include <freeradius-devel/internal/internal.h>
30
31
#include "attrs.h"
32
33
static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out,
34
          fr_dict_attr_t const *parent,
35
          uint8_t const *data, size_t const data_len, UNUSED void *decode_ctx)
36
10.1k
{
37
10.1k
  ssize_t slen;
38
10.1k
  fr_pair_t *vp;
39
40
10.1k
  FR_PROTO_HEX_DUMP(data, data_len, "decode_value");
41
42
10.1k
  vp = fr_pair_afrom_da(ctx, parent);
43
10.1k
  if (!vp) return PAIR_DECODE_OOM;
44
45
10.1k
  slen =  fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
46
10.1k
            &FR_DBUFF_TMP(data, data_len), data_len, true);
47
10.1k
  if (slen < 0) {
48
27
    talloc_free(vp);
49
27
    return slen;
50
27
  }
51
52
10.1k
  fr_assert(vp != NULL);
53
54
10.1k
  vp->vp_tainted = true;
55
10.1k
  fr_pair_append(out, vp);
56
57
10.1k
  return data_len;
58
10.1k
}
59
60
61
/** Decode a raw BFD packet into VPs.
62
 *
63
 */
64
ssize_t fr_bfd_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
65
          uint8_t const *packet, size_t packet_len,
66
          char const *secret, UNUSED size_t secret_len)
67
1.37k
{
68
1.37k
  ssize_t     slen;
69
1.37k
  fr_bfd_ctx_t    packet_ctx;
70
1.37k
  bfd_packet_t const  *bfd;
71
1.37k
  fr_pair_t   *vp;
72
1.37k
  fr_dbuff_t    dbuff;
73
74
1.37k
  packet_ctx.secret = secret;
75
76
1.37k
  bfd = (bfd_packet_t const *) packet;
77
78
1.37k
  slen = fr_struct_from_network(ctx, out, attr_bfd_packet, packet, bfd->length,
79
1.37k
              &packet_ctx, decode_value, NULL);
80
1.37k
  if (slen < 0) return slen;
81
82
1.37k
  if (bfd->length == packet_len) return packet_len;
83
84
  /*
85
   *  Try to decode additional data.
86
   */
87
1.21k
  vp = fr_pair_afrom_da(ctx, attr_bfd_additional_data);
88
1.21k
  if (!vp) return packet_len;
89
90
1.21k
  fr_dbuff_init(&dbuff, packet + slen, packet_len - slen);
91
92
1.21k
  if ((fr_internal_decode_list_dbuff(vp, &vp->vp_group, fr_dict_root(dict_bfd), &dbuff, NULL) < 0) ||
93
657
      (fr_pair_list_num_elements(&vp->vp_group) == 0)) {
94
568
    TALLOC_FREE(vp);
95
643
  } else {
96
643
    fr_pair_append(out, vp);
97
643
  }
98
99
1.21k
  return slen;
100
1.21k
}
101
102
static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
103
         UNUSED fr_dict_attr_t const *root_da)
104
2.93k
{
105
2.93k
  fr_bfd_ctx_t  *test_ctx;
106
107
2.93k
  test_ctx = talloc_zero(ctx, fr_bfd_ctx_t);
108
2.93k
  test_ctx->secret = talloc_strdup(test_ctx, "testing123");
109
2.93k
  test_ctx->tmp_ctx = talloc_zero(test_ctx, uint8_t);
110
111
2.93k
  *out = test_ctx;
112
113
2.93k
  return 0;
114
2.93k
}
115
116
static ssize_t fr_bfd_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out,
117
           uint8_t const *data, size_t data_len, void *proto_ctx)
118
1.42k
{
119
1.42k
  fr_pair_t *vp;
120
1.42k
  bfd_packet_t const *packet;
121
1.42k
  fr_bfd_ctx_t  *test_ctx = talloc_get_type_abort(proto_ctx, fr_bfd_ctx_t);
122
123
1.42k
  if (data_len < FR_BFD_HEADER_LENGTH) {
124
9
    fr_strerror_const("Packet is too small for BFD");
125
9
    return -1;
126
9
  }
127
128
1.41k
  packet = (bfd_packet_t const *) data;
129
130
1.41k
  if (packet->length > data_len) {
131
3
    fr_strerror_const("Packet.length is larger than received data");
132
3
    return -1;
133
3
  }
134
135
1.41k
  if (packet->length < FR_BFD_HEADER_LENGTH) {
136
24
    fr_strerror_const("Packet.length is smaller then BFD header size");
137
24
    return -1;
138
24
  }
139
140
1.39k
  if (packet->version != 1) {
141
4
    fr_strerror_const("Packet.version has invalid value");
142
4
    return -1;
143
4
  }
144
145
1.38k
  if (packet->detect_multi == 0) {
146
1
    fr_strerror_const("Packet.detect-multi has invalid value zero");
147
1
    return -1;
148
1
  }
149
150
1.38k
  if (packet->detect_multi == 0) {
151
0
    fr_strerror_const("Packet.detect-multi has invalid value zero");
152
0
    return -1;
153
0
  }
154
155
1.38k
  if (packet->multipoint != 0) {
156
2
    fr_strerror_const("Packet.multipoint has invalid non-zero value");
157
2
    return -1;
158
2
  }
159
160
1.38k
  if (packet->my_disc == 0) {
161
1
    fr_strerror_const("Packet.my-discriminator has invalid value zero");
162
1
    return -1;
163
1
  }
164
165
1.38k
  if ((packet->your_disc == 0) &&
166
84
      !((packet->state == BFD_STATE_DOWN) ||
167
80
        (packet->state == BFD_STATE_ADMIN_DOWN))) {
168
3
    fr_strerror_const("Packet has invalid values for your-discriminator and state");
169
3
    return 0;
170
3
  }
171
172
  /*
173
   *  Get the packet type.
174
   */
175
1.37k
  vp = fr_pair_afrom_da(ctx, attr_packet_type);
176
1.37k
  if (!vp) {
177
0
    fr_strerror_const("Failed creating Packet-Type");
178
0
    return -1;
179
0
  }
180
181
1.37k
  vp->vp_uint32 = packet->state;
182
1.37k
  fr_pair_append(out, vp);
183
184
#if 0
185
  /*
186
   *  We always decode the packet as a nested VP.
187
   */
188
  vp = fr_pair_afrom_da(ctx, attr_bfd_packet);
189
  if (!vp) {
190
    fr_strerror_const("Failed creating Packet");
191
    return -1;
192
  }
193
  fr_pair_append(out, vp);
194
#endif
195
196
  /* coverity[tainted_data] */
197
1.37k
  return fr_bfd_decode(ctx, out, data, data_len,
198
           test_ctx->secret, talloc_array_length(test_ctx->secret) - 1);
199
1.37k
}
200
201
/*
202
 *  Test points
203
 */
204
extern fr_test_point_proto_decode_t bfd_tp_decode_proto;
205
fr_test_point_proto_decode_t bfd_tp_decode_proto = {
206
  .test_ctx = decode_test_ctx,
207
  .func   = fr_bfd_decode_proto
208
};