The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program 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
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; 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: 1e63dbf0a51538de406cfde701fbcc1d640356ca $
19  * @file src/process/bfd/base.c
20  * @brief BFD processing.
21  *
22  * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
23  */
24 #include <freeradius-devel/server/protocol.h>
25 #include <freeradius-devel/util/debug.h>
26 #include <freeradius-devel/bfd/bfd.h>
27 #include "bfd/session.h"
28 
29 static fr_dict_t const *dict_bfd;
30 
33  { .out = &dict_bfd, .proto = "bfd" },
34  { NULL }
35 };
36 
40 
43  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_bfd},
44 
45  { .out = &attr_bfd_packet, .name = "Packet", .type = FR_TYPE_STRUCT, .dict = &dict_bfd},
46  { .out = &attr_bfd_state, .name = "Packet.state", .type = FR_TYPE_UINT8, .dict = &dict_bfd},
47 
48  { NULL }
49 };
50 
51 #define SECTION(_x) \
52  CONF_SECTION *recv_ ## _x; \
53  CONF_SECTION *send_ ## _x
54 
55 typedef struct {
56  uint64_t nothing; // so that the next field isn't at offset 0
57 
58  SECTION(admin_down);
59  SECTION(down);
61  SECTION(up);
63 
64 typedef struct {
65  bool unused;
66 
69 
70 #define PROCESS_PACKET_TYPE fr_bfd_packet_code_t
71 #define PROCESS_CODE_MAX FR_BFD_CODE_MAX
72 #define PROCESS_PACKET_CODE_VALID FR_BFD_PACKET_CODE_VALID
73 #define PROCESS_INST process_bfd_t
74 
75 #define PROCESS_SEND_RECV (1)
76 
77 #include <freeradius-devel/server/process.h>
78 
79 /*
80  * Debug the packet if requested.
81  */
82 static void bfd_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
83 {
84 #ifdef WITH_IFINDEX_NAME_RESOLUTION
85  char if_name[IFNAMSIZ];
86 #endif
87 
88  if (!packet) return;
89  if (!RDEBUG_ENABLED) return;
90 
91  log_request(L_DBG, L_DBG_LVL_1, request, __FILE__, __LINE__, "%s %s ID %d from %s%pV%s:%i to %s%pV%s:%i "
92 #ifdef WITH_IFINDEX_NAME_RESOLUTION
93  "%s%s%s"
94 #endif
95  "",
96  received ? "Received" : "Sending",
97  fr_bfd_packet_names[packet->code],
98  packet->id,
99  packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "",
100  fr_box_ipaddr(packet->socket.inet.src_ipaddr),
101  packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "",
102  packet->socket.inet.src_port,
103  packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "",
104  fr_box_ipaddr(packet->socket.inet.dst_ipaddr),
105  packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "",
106  packet->socket.inet.dst_port
107 #ifdef WITH_IFINDEX_NAME_RESOLUTION
108  , packet->socket.inet.ifindex ? "via " : "",
109  packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "",
110  packet->socket.inet.ifindex ? " " : ""
111 #endif
112  );
113 
114  if (received || request->parent) {
115  log_request_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
116  } else {
117  log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
118  }
119 }
120 
121 RESUME_NO_MCTX(recv_bfd)
122 {
123  rlm_rcode_t rcode = *p_result;
124  fr_pair_t *vp;
125  uint32_t state = 0;
126 
128 
130 
131  if (rcode == RLM_MODULE_FAIL) {
132  state = FR_BFD_ADMIN_DOWN;
133  } else {
134  /*
135  * Check for a state / reply code.
136  */
137  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
138  if (vp) {
139  state = vp->vp_uint32;
140  } else {
141  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_bfd_packet);
142  if (vp) vp = fr_pair_find_by_da_nested(&vp->vp_group, NULL, attr_bfd_state);
143  if (vp) state = vp->vp_uint8;
144  }
145  }
146 
148 
149  request->reply->code = state;
150 
151  request->reply->timestamp = fr_time();
152 
154 }
155 
156 
157 /*
158  * recv FOO
159  */
160 static fr_process_state_t const process_state_packet[] = {
161  [ FR_BFD_ADMIN_DOWN ] = {
162  .default_reply = FR_BFD_DOWN,
163  .rcode = RLM_MODULE_NOOP,
164  .recv = recv_generic,
165  .resume = resume_recv_bfd,
166  .section_offset = offsetof(process_bfd_sections_t, recv_admin_down),
167  },
168 
169  [ FR_BFD_DOWN ] = {
170  .default_reply = FR_BFD_DOWN,
171  .rcode = RLM_MODULE_NOOP,
172  .recv = recv_generic,
173  .resume = resume_recv_bfd,
174  .section_offset = offsetof(process_bfd_sections_t, recv_down),
175  },
176 
177  [ FR_BFD_INIT ] = {
178  .default_reply = FR_BFD_UP,
179  .rcode = RLM_MODULE_NOOP,
180  .recv = recv_generic,
181  .resume = resume_recv_bfd,
182  .section_offset = offsetof(process_bfd_sections_t, recv_init),
183  },
184 
185  [ FR_BFD_UP ] = {
186  .default_reply = FR_BFD_UP,
187  .rcode = RLM_MODULE_NOOP,
188  .recv = recv_generic,
189  .resume = resume_recv_bfd,
190  .section_offset = offsetof(process_bfd_sections_t, recv_up),
191  },
192 };
193 
194 /*
195  * send FOO
196  */
197 static fr_process_state_t const process_state_reply[] = {
198  [ FR_BFD_ADMIN_DOWN ] = {
199  .rcode = RLM_MODULE_NOOP,
200  .send = send_generic,
201  .resume = resume_send_generic,
202  .section_offset = offsetof(process_bfd_sections_t, send_admin_down),
203  },
204 
205  [ FR_BFD_DOWN ] = {
206  .rcode = RLM_MODULE_NOOP,
207  .send = send_generic,
208  .resume = resume_send_generic,
209  .section_offset = offsetof(process_bfd_sections_t, send_down),
210  },
211 
212  [ FR_BFD_INIT ] = {
213  .rcode = RLM_MODULE_NOOP,
214  .send = send_generic,
215  .resume = resume_send_generic,
216  .section_offset = offsetof(process_bfd_sections_t, send_init),
217  },
218 
219  [ FR_BFD_UP ] = {
220  .rcode = RLM_MODULE_NOOP,
221  .send = send_generic,
222  .resume = resume_send_generic,
223  .section_offset = offsetof(process_bfd_sections_t, send_up),
224  },
225 };
226 
227 static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
228 {
229  fr_process_state_t const *state;
230  bfd_wrapper_t const *wrapper;
231 
233 
235  fr_assert(PROCESS_PACKET_CODE_VALID(request->packet->code));
236 
237  request->component = "bfd";
238  request->module = NULL;
239 
240  fr_assert(request->dict == dict_bfd);
241 
242  wrapper = (bfd_wrapper_t const *) request->packet->data;
243 
244  /*
245  * If there's no packet, we must be calling the "send" routine
246  */
247  if (wrapper->type == BFD_WRAPPER_SEND_PACKET) {
249 
250  UPDATE_STATE(reply);
251 
252  bfd_packet_debug(request, request->reply, &request->reply_pairs, false);
253  return state->send(p_result, mctx, request);
254  }
255 
257 
258  UPDATE_STATE(packet);
259 
260  if (!state->recv) {
261  REDEBUG("Invalid packet type (%u)", request->packet->code);
263  }
264 
265  bfd_packet_debug(request, request->packet, &request->request_pairs, true);
266 
267  return state->recv(p_result, mctx, request);
268 }
269 
270 /*
271  * We send and receive the same packet types.
272  */
273 #define SEND_RECV(_x, _y) \
274  { \
275  .section = SECTION_NAME("recv", _x), \
276  .actions = &mod_actions_postauth, \
277  .offset = PROCESS_CONF_OFFSET(recv_ ## _y), \
278  }, \
279  { \
280  .section = SECTION_NAME("send", _x), \
281  .actions = &mod_actions_postauth, \
282  .offset = PROCESS_CONF_OFFSET(send_ ## _y), \
283  }
284 
286  SEND_RECV("Admin-Down", admin_down),
287  SEND_RECV("Down", down),
288  SEND_RECV("Init", init),
289  SEND_RECV("Up", up),
290 
292 };
293 
294 
297  .common = {
298  .magic = MODULE_MAGIC_INIT,
299  .name = "bfd",
300  .inst_size = sizeof(process_bfd_t),
301  },
302  .process = mod_process,
303  .compile_list = compile_list,
304  .dict = &dict_bfd,
305 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition: action.h:37
@ FR_BFD_INIT
Definition: bfd.h:146
@ FR_BFD_ADMIN_DOWN
Definition: bfd.h:144
@ FR_BFD_UP
Definition: bfd.h:147
@ FR_BFD_DOWN
Definition: bfd.h:145
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
if(rcode > 0)
Definition: fd_read.h:9
fr_dict_attr_t const * attr_packet_type
Definition: base.c:91
void log_request_proto_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a list of protocol fr_pair_ts.
Definition: log.c:854
void log_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt,...)
Marshal variadic log arguments into a va_list and pass to normal logging functions.
Definition: log.c:612
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition: log.c:830
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition: log.h:70
@ L_DBG
Only displayed when debugging is enabled.
Definition: log.h:59
@ BFD_WRAPPER_SEND_PACKET
Definition: session.h:127
@ BFD_WRAPPER_RECV_PACKET
Definition: session.h:126
uint32_t type
Definition: session.h:142
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
unsigned int uint32_t
Definition: merged_model.c:33
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
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
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition: pair.c:770
fr_dict_autoload_t process_bfd_dict[]
Definition: base.c:32
static fr_dict_attr_t const * attr_bfd_packet
Definition: base.c:38
static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: base.c:227
process_bfd_sections_t sections
Definition: base.c:67
fr_process_module_t process_bfd
Definition: base.c:296
bool unused
Definition: base.c:65
static const virtual_server_compile_t compile_list[]
Definition: base.c:285
static void bfd_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition: base.c:82
static fr_dict_attr_t const * attr_bfd_state
Definition: base.c:39
static fr_process_state_t const process_state_reply[]
Definition: base.c:197
fr_dict_attr_autoload_t process_bfd_dict_attr[]
Definition: base.c:42
static fr_dict_t const * dict_bfd
Definition: base.c:29
#define SEND_RECV(_x, _y)
Definition: base.c:273
#define PROCESS_PACKET_CODE_VALID
Definition: base.c:72
static fr_process_state_t const process_state_packet[]
Definition: base.c:160
RESUME_NO_MCTX(recv_bfd)
Definition: base.c:121
#define PROCESS_TRACE
Trace each state function as it's entered.
Definition: process.h:65
module_t common
Common fields for all loadable modules.
Definition: process.h:55
Common public symbol definition for all process modules.
Definition: process.h:54
char const * fr_bfd_packet_names[FR_BFD_CODE_MAX]
Definition: base.c:63
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG_ENABLED()
Definition: radclient.h:49
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition: rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition: rcode.h:50
void * data
Module's instance data.
Definition: module.h:271
RETURN_MODULE_FAIL
fr_assert(0)
init
Enter the EAP-IDENTITY state.
Definition: state_machine.c:90
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
uint64_t nothing
Definition: base.c:56
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
#define talloc_get_type_abort_const
Definition: talloc.h:282
unsigned int code
Packet code (type).
Definition: packet.h:61
fr_socket_t socket
This packet was received on.
Definition: packet.h:57
int id
Packet ID (used to link requests/responses).
Definition: packet.h:60
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition: socket.h:78
#define fr_box_ipaddr(_val)
Definition: value.h:294
#define COMPILE_TERMINATOR
Processing sections which are allowed in this virtual server.