Coverage Report

Created: 2026-08-08 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: 0bdca730049e0adff4aeff866cc51050325b8551 $
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: 0bdca730049e0adff4aeff866cc51050325b8551 $")
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.8k
{
37
10.8k
  ssize_t slen;
38
10.8k
  fr_pair_t *vp;
39
40
10.8k
  FR_PROTO_HEX_DUMP(data, data_len, "decode_value");
41
42
10.8k
  vp = fr_pair_afrom_da(ctx, parent);
43
10.8k
  if (!vp) return PAIR_DECODE_OOM;
44
45
10.8k
  slen =  fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
46
10.8k
            &FR_DBUFF_TMP(data, data_len), data_len, true);
47
10.8k
  if (slen < 0) {
48
68
    talloc_free(vp);
49
68
    return slen;
50
68
  }
51
52
10.7k
  fr_assert(vp != NULL);
53
54
10.7k
  vp->vp_tainted = true;
55
10.7k
  fr_pair_append(out, vp);
56
57
10.7k
  return data_len;
58
10.8k
}
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.45k
{
68
1.45k
  ssize_t     slen;
69
1.45k
  fr_bfd_ctx_t    packet_ctx;
70
1.45k
  bfd_packet_t const  *bfd;
71
1.45k
  fr_pair_t   *vp;
72
1.45k
  fr_dbuff_t    dbuff;
73
74
1.45k
  packet_ctx.secret = secret;
75
76
1.45k
  bfd = (bfd_packet_t const *) packet;
77
78
1.45k
  slen = fr_struct_from_network(ctx, out, attr_bfd_packet, packet, bfd->length,
79
1.45k
              &packet_ctx, decode_value, NULL);
80
1.45k
  if (slen < 0) return slen;
81
82
1.45k
  if (bfd->length == packet_len) return packet_len;
83
84
  /*
85
   *  Try to decode additional data.
86
   */
87
1.29k
  vp = fr_pair_afrom_da(ctx, attr_bfd_additional_data);
88
1.29k
  if (!vp) return packet_len;
89
90
1.29k
  fr_dbuff_init(&dbuff, packet + slen, packet_len - slen);
91
92
1.29k
  if ((fr_internal_decode_list_dbuff(vp, &vp->vp_group, fr_dict_root(dict_bfd), &dbuff, NULL) < 0) ||
93
701
      (fr_pair_list_num_elements(&vp->vp_group) == 0)) {
94
590
    TALLOC_FREE(vp);
95
701
  } else {
96
701
    fr_pair_append(out, vp);
97
701
  }
98
99
1.29k
  return packet_len;
100
1.29k
}
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
3.02k
{
105
3.02k
  fr_bfd_ctx_t  *test_ctx;
106
107
3.02k
  test_ctx = talloc_zero(ctx, fr_bfd_ctx_t);
108
3.02k
  test_ctx->secret = talloc_strdup(test_ctx, "testing123");
109
3.02k
  test_ctx->tmp_ctx = talloc_zero(test_ctx, uint8_t);
110
111
3.02k
  *out = test_ctx;
112
113
3.02k
  return 0;
114
3.02k
}
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.50k
{
119
1.50k
  fr_pair_t *vp;
120
1.50k
  bfd_packet_t const *packet;
121
1.50k
  fr_bfd_ctx_t  *test_ctx = talloc_get_type_abort(proto_ctx, fr_bfd_ctx_t);
122
123
1.50k
  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.49k
  packet = (bfd_packet_t const *) data;
129
130
1.49k
  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.48k
  if (packet->length < FR_BFD_HEADER_LENGTH) {
136
23
    fr_strerror_const("Packet.length is smaller then BFD header size");
137
23
    return -1;
138
23
  }
139
140
1.46k
  if (packet->version != 1) {
141
5
    fr_strerror_const("Packet.version has invalid value");
142
5
    return -1;
143
5
  }
144
145
1.46k
  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.46k
  if (packet->multipoint != 0) {
151
1
    fr_strerror_const("Packet.multipoint has invalid non-zero value");
152
1
    return -1;
153
1
  }
154
155
1.45k
  if (packet->my_disc == 0) {
156
1
    fr_strerror_const("Packet.my-discriminator has invalid value zero");
157
1
    return -1;
158
1
  }
159
160
1.45k
  if ((packet->your_disc == 0) &&
161
68
      !((packet->state == BFD_STATE_DOWN) ||
162
58
        (packet->state == BFD_STATE_ADMIN_DOWN))) {
163
5
    fr_strerror_const("Packet has invalid values for your-discriminator and state");
164
5
    return -1;
165
5
  }
166
167
  /*
168
   *  Get the packet type.
169
   */
170
1.45k
  vp = fr_pair_afrom_da(ctx, attr_packet_type);
171
1.45k
  if (!vp) {
172
0
    fr_strerror_const("Failed creating Packet-Type");
173
0
    return -1;
174
0
  }
175
176
1.45k
  vp->vp_uint32 = packet->state;
177
1.45k
  fr_pair_append(out, vp);
178
179
#if 0
180
  /*
181
   *  We always decode the packet as a nested VP.
182
   */
183
  vp = fr_pair_afrom_da(ctx, attr_bfd_packet);
184
  if (!vp) {
185
    fr_strerror_const("Failed creating Packet");
186
    return -1;
187
  }
188
  fr_pair_append(out, vp);
189
#endif
190
191
  /* coverity[tainted_data] */
192
1.45k
  return fr_bfd_decode(ctx, out, data, data_len,
193
1.45k
           test_ctx->secret, talloc_strlen(test_ctx->secret));
194
1.45k
}
195
196
/*
197
 *  Test points
198
 */
199
extern fr_test_point_proto_decode_t bfd_tp_decode_proto;
200
fr_test_point_proto_decode_t bfd_tp_decode_proto = {
201
  .test_ctx = decode_test_ctx,
202
  .func   = fr_bfd_decode_proto
203
};