Coverage Report

Created: 2026-09-28 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/server/packet.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
/** fr_packet_t alloc/free functions
18
 *
19
 * @file src/lib/server/packet.c
20
 *
21
 * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
22
 */
23
24
RCSID("$Id: 2cdcfb311d13d9cc652b3357ea5fe62a1650d87c $")
25
26
#include <freeradius-devel/util/atexit.h>
27
#include <freeradius-devel/util/pair_legacy.h>
28
29
#include <freeradius-devel/server/packet.h>
30
31
static fr_dict_t const *dict_freeradius;
32
33
extern fr_dict_autoload_t util_packet_dict[];
34
fr_dict_autoload_t util_packet_dict[] = {
35
  { .out = &dict_freeradius, .proto = "freeradius" },
36
  DICT_AUTOLOAD_TERMINATOR
37
};
38
39
static fr_dict_attr_t const *attr_net;
40
static fr_dict_attr_t const *attr_net_src;
41
static fr_dict_attr_t const *attr_net_src_ip;
42
static fr_dict_attr_t const *attr_net_src_port;
43
static fr_dict_attr_t const *attr_net_dst;
44
static fr_dict_attr_t const *attr_net_dst_ip;
45
static fr_dict_attr_t const *attr_net_dst_port;
46
static fr_dict_attr_t const *attr_net_timestamp;
47
static fr_dict_attr_t const *attr_net_interface;
48
49
extern fr_dict_attr_autoload_t util_packet_dict_attr[];
50
fr_dict_attr_autoload_t util_packet_dict_attr[] = {
51
  { .out = &attr_net, .name = "Net", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
52
  { .out = &attr_net_src, .name = "Net.Src", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
53
  { .out = &attr_net_dst, .name = "Net.Dst", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
54
  { .out = &attr_net_src_ip, .name = "Net.Src.IP", .type = FR_TYPE_COMBO_IP_ADDR, .dict = &dict_freeradius },
55
  { .out = &attr_net_src_port, .name = "Net.Src.Port", .type = FR_TYPE_UINT16, .dict = &dict_freeradius },
56
  { .out = &attr_net_dst_ip, .name = "Net.Dst.IP", .type = FR_TYPE_COMBO_IP_ADDR, .dict = &dict_freeradius },
57
  { .out = &attr_net_dst_port, .name = "Net.Dst.Port", .type = FR_TYPE_UINT16, .dict = &dict_freeradius },
58
  { .out = &attr_net_timestamp, .name = "Net.Timestamp", .type = FR_TYPE_DATE, .dict = &dict_freeradius },
59
  { .out = &attr_net_interface, .name = "Net.Interface", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
60
61
  DICT_AUTOLOAD_TERMINATOR
62
};
63
64
static int inet2pairs(TALLOC_CTX *ctx, fr_pair_list_t *list,
65
          fr_dict_attr_t const *attr_ip, fr_dict_attr_t const *attr_port,
66
          fr_ipaddr_t const *ipaddr, uint16_t port)
67
0
{
68
0
  fr_pair_t *vp;
69
70
0
  if (fr_pair_find_or_append_by_da(ctx, &vp, list, attr_ip) < 0) return -1;
71
0
  if (fr_value_box_ipaddr(&vp->data, attr_ip, ipaddr, false) < 0) return -1;
72
0
  fr_pair_set_immutable(vp);
73
74
0
  if (fr_pair_find_or_append_by_da(ctx, &vp, list, attr_port) < 0) return -1;
75
0
  vp->vp_uint16 = port;
76
0
  fr_pair_set_immutable(vp);
77
78
0
  return 0;
79
0
}
80
81
/** Allocate a "Net." struct with src/dst host and port.
82
 *
83
 * @param      ctx    The context in which the packet is allocated.
84
 * @param[in]  list   #fr_pair_list_t value to resolve to #fr_packet_t.
85
 * @param[out] packet The request packet.
86
 *
87
 * @return
88
 *  -  0 on success
89
 *  - <0 on error.
90
 */
91
int fr_packet_pairs_from_packet(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_packet_t const *packet)
92
0
{
93
0
  fr_pair_t *vp, *net, *tlv;
94
0
#ifdef WITH_IFINDEX_NAME_RESOLUTION
95
0
  char if_name[IFNAMSIZ];
96
0
#endif
97
98
  /*
99
   *  Net
100
   */
101
0
  if (fr_pair_find_or_append_by_da(ctx, &net, list, attr_net) < 0) return -1;
102
103
  /*
104
   *  Net.Src
105
   *
106
   *  Only create the address attributes if the packet
107
   *  actually has a source address.  Layer 2 protocols
108
   *  (e.g. ARP) leave the inet addresses unset, in which
109
   *  case fr_value_box_ipaddr() would fail.
110
   */
111
0
   if (packet->socket.inet.src_ipaddr.af != AF_UNSPEC) {
112
0
    if (fr_pair_find_or_append_by_da(net, &tlv, &net->vp_group, attr_net_src) < 0) return -1;
113
114
0
    if (inet2pairs(tlv, &tlv->vp_group, attr_net_src_ip, attr_net_src_port, &packet->socket.inet.src_ipaddr, packet->socket.inet.src_port) < 0) return -1;
115
0
   }
116
117
  /*
118
   *  Net.Dst
119
   */
120
0
   if (packet->socket.inet.dst_ipaddr.af != AF_UNSPEC) {
121
0
    if (fr_pair_find_or_append_by_da(net, &tlv, &net->vp_group, attr_net_dst) < 0) return -1;
122
123
0
    if (inet2pairs(tlv, &tlv->vp_group, attr_net_dst_ip, attr_net_dst_port, &packet->socket.inet.dst_ipaddr, packet->socket.inet.dst_port) < 0) return -1;
124
0
   }
125
  /*
126
   *  Timestamp
127
   */
128
0
  if (fr_pair_find_or_append_by_da(net, &vp, &net->vp_group, attr_net_timestamp) < 0) return -1;
129
0
  vp->vp_date = fr_time_to_unix_time(packet->timestamp);
130
0
  fr_pair_set_immutable(vp);
131
132
0
#ifdef WITH_IFINDEX_NAME_RESOLUTION
133
  /*
134
   *  Interface
135
   */
136
0
  if (!packet->socket.inet.ifindex) return 0;
137
0
  if (fr_pair_find_or_append_by_da(net, &vp, &net->vp_group, attr_net_interface) < 0) return -1;
138
0
  fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex);
139
0
  fr_value_box_strdup(vp, &vp->data, NULL, if_name, false);
140
0
#endif
141
142
0
  return 0;
143
0
}
144
145
static void pairs2inet(fr_ipaddr_t *ipaddr, uint16_t *port, fr_pair_list_t const *list,
146
           fr_dict_attr_t const *attr_ip, fr_dict_attr_t const *attr_port)
147
0
{
148
0
  fr_pair_t *vp;
149
150
0
  vp = fr_pair_find_by_da(list, NULL, attr_ip);
151
0
  if (vp) *ipaddr = vp->vp_ip;
152
153
0
  vp = fr_pair_find_by_da(list, NULL, attr_port);
154
0
  if (vp) *port = vp->vp_uint16;
155
0
}
156
157
/** Convert pairs to information in a packet.
158
 *
159
 * @param packet  the packet to send
160
 * @param list    the list to check for Net.*
161
 */
162
void fr_packet_net_from_pairs(fr_packet_t *packet, fr_pair_list_t const *list)
163
0
{
164
0
  fr_pair_t *net, *tlv;
165
166
0
  net = fr_pair_find_by_da(list, NULL, attr_net);
167
0
  if (!net) return;
168
169
0
  tlv = fr_pair_find_by_da(&net->vp_group, NULL, attr_net_src);
170
0
  if (tlv) {
171
0
    pairs2inet(&packet->socket.inet.src_ipaddr, &packet->socket.inet.src_port, &tlv->vp_group,
172
0
         attr_net_src_ip, attr_net_src_port);
173
0
  }
174
175
0
  tlv = fr_pair_find_by_da(&net->vp_group, NULL, attr_net_dst);
176
0
  if (tlv) {
177
0
    pairs2inet(&packet->socket.inet.dst_ipaddr, &packet->socket.inet.dst_port, &tlv->vp_group,
178
0
         attr_net_dst_ip, attr_net_dst_port);
179
0
  }
180
0
}
181
182
static int _packet_global_free(UNUSED void *uctx)
183
0
{
184
0
  fr_dict_autofree(util_packet_dict);
185
186
0
  return 0;
187
0
}
188
189
static int _packet_global_init(UNUSED void *uctx)
190
0
{
191
0
  if (fr_dict_autoload(util_packet_dict) < 0) {
192
0
  error:
193
0
    fr_perror("packet_global_init");
194
0
    return -1;
195
0
  }
196
197
0
  if (fr_dict_attr_autoload(util_packet_dict_attr) < 0) goto error;
198
199
0
  return 0;
200
0
}
201
202
/** Initialises the Net. packet attributes.
203
 *
204
 * @return
205
 *  - 0 on success.
206
 *  - -1 on failure.
207
 */
208
int packet_global_init(void)
209
0
{
210
0
  int ret;
211
212
0
  fr_atexit_global_once_ret(&ret, _packet_global_init, _packet_global_free, NULL);
213
214
0
  return ret;
215
0
}