The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
session.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/**
19 * $Id: 2589d64d10447d97778ccc36e25d3914f35c7c5c $
20 * @file src/listen/bfd/session.c
21 * @brief BFD Session handling
22 *
23 * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
24 */
25
26#include <freeradius-devel/util/debug.h>
27
28#include <freeradius-devel/util/time.h>
29#include <freeradius-devel/util/event.h>
30#include <freeradius-devel/util/base16.h>
31#include <freeradius-devel/util/md5.h>
32#include <freeradius-devel/util/rand.h>
33#include <freeradius-devel/util/sha1.h>
34#include <freeradius-devel/util/socket.h>
35#include <freeradius-devel/util/time.h>
36
37#include "session.h"
38
39static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd);
40static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd);
41static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd);
42
44
45static void bfd_start_packets(bfd_session_t *session);
46static void bfd_start_control(bfd_session_t *session);
47static int bfd_stop_control(bfd_session_t *session);
48static void bfd_set_timeout(bfd_session_t *session, fr_time_t when);
49
50/*
51 * Wrapper to run a trigger.
52 *
53 * @todo - push the trigger name, and various other VPs to the worker side?
54 * we will need to define some other kind of fake packet to send to the process
55 * module.
56 */
58{
59#if 0
60 bfd_wrapper_t wrapper;
61 fr_io_track_t *track;
62
64 wrapper.state_change = change;
65 wrapper.session = session;
66
67 track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
68 &session->client.src_ipaddr, session->port);
69 if (!track) return;
70
71 (void) fr_network_sendto_worker(session->nr, session->listen, track, (uint8_t const *) &wrapper, sizeof(wrapper), fr_time());
72#endif
73}
74
82
83
84/*
85 * Stop polling for packets.
86 */
87static int bfd_stop_poll(bfd_session_t *session)
88{
89 if (!session->doing_poll) return 0;
90
91 session->doing_poll = false;
92
93 /*
94 * We tried to increase the min_tx during a polling
95 * sequence. That isn't kosher, so we instead waited
96 * until now.
97 */
101 }
102
103 /*
104 * Already sending packets. Clear the poll bit and
105 * re-set the timers.
106 */
107 if (!session->remote_demand_mode) {
108 fr_assert(session->timeout_ev != NULL);
109 fr_assert(session->packet_ev != NULL);
110
111 bfd_stop_control(session);
112 bfd_start_control(session);
113 return 1;
114 }
115
116 return bfd_stop_control(session);
117}
118
119/*
120 * Send an immediate response to a poll request.
121 *
122 * Note that this doesn't affect our "last_sent" timer.
123 * That's set only when we intend to send a packet.
124 */
125static void bfd_poll_response(bfd_session_t *session)
126{
127 bfd_packet_t bfd;
128
129 bfd_control_packet_init(session, &bfd);
130 bfd.poll = 0; /* Section 6.5 */
131 bfd.final = 1;
132
133 /*
134 * TO DO: rate limit poll responses.
135 */
136
137 bfd_sign(session, &bfd);
138
139 if (sendfromto(session->sockfd, &bfd, bfd.length, 0, 0,
140 (struct sockaddr *) &session->local_sockaddr, session->local_salen,
141 (struct sockaddr *) &session->remote_sockaddr, session->remote_salen) < 0) {
142 ERROR("Failed sending packet: %s", fr_syserror(errno));
143 bfd_session_admin_down(session);
144 }
145}
146
147/*
148 * Implement the requirements of RFC 5880 Section 6.8.6.
149 */
151{
153
154 /*
155 *
156 * If the Your Discriminator field is nonzero, it MUST be used to
157 * select the session with which this BFD packet is associated. If
158 * no session is found, the packet MUST be discarded.
159 */
160 if ((bfd->your_disc != 0) && (bfd->your_disc != session->local_disc)) {
161 DEBUG("BFD %s peer %s packet has unexpected Your-Discriminator (got %08x, expected %08x",
162 session->server_name, session->client.shortname, bfd->your_disc, session->local_disc);
164 }
165
166 /*
167 * If the A bit is set and no authentication is in use (bfd.AuthType
168 * is zero), the packet MUST be discarded.
169 */
170 if (bfd->auth_present &&
171 (session->auth_type == BFD_AUTH_RESERVED)) {
172 DEBUG("BFD %s peer %s packet asked to authenticate an unauthenticated session.",
173 session->server_name, session->client.shortname);
175 }
176
177 /*
178 * If the A bit is clear and authentication is in use (bfd.AuthType
179 * is nonzero), the packet MUST be discarded.
180 */
181 if (!bfd->auth_present &&
182 (session->auth_type != BFD_AUTH_RESERVED)) {
183 DEBUG("BFD %s peer %s packet failed to authenticate an authenticated session.",
184 session->server_name, session->client.shortname);
186 }
187
188 /*
189 * If the A bit is set, the packet MUST be authenticated under the
190 * rules of section 6.7, based on the authentication type in use
191 * (bfd.AuthType). This may cause the packet to be discarded.
192 */
193 if (bfd->auth_present && !bfd_authenticate(session, bfd)) {
194 DEBUG("BFD %s peer %s authentication failed for packet",
195 session->server_name, session->client.shortname);
197 }
198
199 /*
200 * Set bfd.RemoteDiscr to the value of My Discriminator.
201 *
202 * Set bfd.RemoteState to the value of the State (Sta) field.
203 *
204 * Set bfd.RemoteDemandMode to the value of the Demand (D) bit.
205 */
206 session->remote_disc = bfd->my_disc;
207 session->remote_session_state = (bfd_session_state_t)bfd->state;
208 session->remote_demand_mode = bfd->demand;
209
210 /*
211 * Set bfd.RemoteMinRxInterval to the value of Required Min RX
212 * Interval.
213 *
214 * Addendum: clamp it to be between 32ms and 1s.
215 */
216 if ((bfd->required_min_rx_interval > 32) && (bfd->required_min_rx_interval < USEC)) {
217 session->remote_min_rx_interval = fr_time_delta_from_usec(bfd->required_min_rx_interval);
218 }
219
220 /*
221 * If the Required Min Echo RX Interval field is zero, the
222 * transmission of Echo packets, if any, MUST cease.
223 */
224 if (bfd->min_echo_rx_interval == 0) {
225#if 0
226 /*
227 * Echo packets are BFD packets with
228 * application-layer data echoed back to the
229 * sender. We don't do that.
230 */
231 bfd_stop_echo(session);
232#endif
233 }
234
235 /*
236 * If a Poll Sequence is being transmitted by the local system and
237 * the Final (F) bit in the received packet is set, the Poll Sequence
238 * MUST be terminated.
239 */
240 if (session->doing_poll && bfd->final) {
241 bfd_stop_poll(session);
242 }
243
244 /*
245 * Update transmit intervals as in 6.8.2
246 */
247
248 /*
249 * Update detection times as in 6.8.4
250 */
251 if (!session->demand_mode) {
252 if (fr_time_delta_gteq(session->required_min_rx_interval, fr_time_delta_from_usec(bfd->desired_min_tx_interval))) {
253 session->detection_time = session->required_min_rx_interval;
254 } else {
255 session->detection_time = fr_time_delta_from_usec(bfd->desired_min_tx_interval);
256 }
257 } else {
259 session->detection_time = session->desired_min_tx_interval;
260 } else {
261 session->detection_time = session->remote_min_rx_interval;
262 }
263 }
264
265 /*
266 * If bfd.SessionState is AdminDown
267 *
268 * Discard the packet.
269 */
270 if (session->session_state == BFD_STATE_ADMIN_DOWN) {
271 DEBUG("Discarding BFD packet (admin down)");
273 }
274
275 /*
276 * If received state is AdminDown
277 * If bfd.SessionState is not Down
278 * Set bfd.LocalDiag to 3 (Neighbor signaled session down)
279 * Set bfd.SessionState to Down
280 */
281 if (bfd->state == BFD_STATE_ADMIN_DOWN) {
282 if (session->session_state != BFD_STATE_DOWN) {
283 down:
284 session->local_diag = BFD_NEIGHBOR_DOWN;
285
286 DEBUG("BFD %s peer %s State %s -> DOWN (neighbour %s)",
287 session->server_name, session->client.shortname,
289 fr_bfd_packet_names[bfd->state]);
290 session->session_state = BFD_STATE_DOWN;
291 state_change = BFD_STATE_CHANGE_PEER_DOWN;
292 }
293
294 } else {
295 switch (session->session_state) {
296 case BFD_STATE_DOWN:
297 switch (bfd->state) {
298 case BFD_STATE_DOWN:
299 DEBUG("BFD %s peer %s State DOWN -> INIT (neighbor DOWN)",
300 session->server_name, session->client.shortname);
301 session->session_state = BFD_STATE_INIT;
302 state_change = BFD_STATE_CHANGE_INIT;
303 break;
304
305 case BFD_STATE_INIT:
306 DEBUG("BFD %s peer %s State DOWN -> UP (neighbor INIT)",
307 session->server_name, session->client.shortname);
308 session->session_state = BFD_STATE_UP;
309 state_change = BFD_STATE_CHANGE_UP;
310 break;
311
312 default: /* don't change anything */
313 break;
314 }
315 break;
316
317 case BFD_STATE_INIT:
318 switch (bfd->state) {
319 case BFD_STATE_INIT:
320 case BFD_STATE_UP:
321 DEBUG("BFD %s peer %s State INIT -> UP",
322 session->server_name, session->client.shortname);
323 session->session_state = BFD_STATE_UP;
324 state_change = BFD_STATE_CHANGE_UP;
325 break;
326
327 default: /* don't change anything */
328 break;
329 }
330 break;
331
332 case BFD_STATE_UP:
333 switch (bfd->state) {
334 case BFD_STATE_DOWN:
335 goto down;
336
337 default:
338 break;
339 }
340 break;
341
342 default:
343 DEBUG("Internal sanity check failed");
345 }
346 }
347
348 /*
349 * Section 6.8.3
350 *
351 * When bfd.SessionState is not Up, the system MUST set
352 * bfd.DesiredMinTxInterval to a value of not less than one second
353 * (1,000,000 microseconds). This is intended to ensure that the
354 * bandwidth consumed by BFD sessions that are not Up is negligible,
355 * particularly in the case where a neighbor may not be running BFD.
356 */
357 if (state_change && (session->session_state != BFD_STATE_UP)) {
359 }
360
361 /*
362 * Check if demand mode should be active (Section 6.6)
363 *
364 * If bfd.RemoteDemandMode is 1, bfd.SessionState is Up, and
365 * bfd.RemoteSessionState is Up, Demand mode is active on the remote
366 * system and the local system MUST cease the periodic transmission
367 * of BFD Control packets (see section 6.8.7).
368 */
369 if (session->remote_demand_mode &&
370 (session->session_state == BFD_STATE_UP) &&
371 (session->remote_session_state == BFD_STATE_UP)) {
372 DEBUG("BFD %s peer %s demand mode UP / UP, stopping packets",
373 session->server_name, session->client.shortname);
374 bfd_stop_control(session);
375 }
376
377 /*
378 * If bfd.RemoteDemandMode is 0, or bfd.SessionState is not Up, or
379 * bfd.RemoteSessionState is not Up, Demand mode is not active on the
380 * remote system and the local system MUST send periodic BFD Control
381 * packets.
382 */
383 if ((!session->remote_demand_mode) ||
384 (session->session_state != BFD_STATE_UP) ||
385 (session->remote_session_state != BFD_STATE_UP)) {
386 bfd_start_control(session);
387 }
388
389 /*
390 * If the Poll (P) bit is set, send a BFD Control packet to the
391 * remote system with the Poll (P) bit clear, and the Final (F) bit
392 * set (see section 6.8.7).
393 */
394 if (bfd->poll) {
395 bfd_poll_response(session);
396 }
397
398 /*
399 * If the packet was not discarded, it has been received for purposes
400 * of the Detection Time expiration rules in section 6.8.4.
401 */
402 session->last_recv = fr_time();
403
404 /*
405 * The other end is reducing the RX interval. Do that
406 * now.
407 */
408 if (fr_time_delta_lt(fr_time_delta_from_usec(bfd->required_min_rx_interval), session->remote_min_rx_interval) &&
409 !session->demand_mode) {
410 bfd_stop_control(session);
411 bfd_start_control(session);
412 }
413
414 /*
415 * @todo - warn about missing packets?
416 */
417#if 0
418 if ((session->detect_multi >= 2) && (fr_time_gt(session->last_recv, session->next_recv))) {
419 ...
420 }
421#endif
422
423 return state_change;
424}
425
426
427/*
428 * Requirements of 6.8.3
429 *
430 * Changes to:
431 *
432 * session->desired_min_tx_interval
433 * session->required_min_rx_interval
434 *
435 * mean we start polling.
436 */
437
438/*
439 * Verify and/or calculate passwords
440 */
441static void bfd_calc_simple(bfd_session_t *session, bfd_packet_t *bfd)
442{
443 bfd_auth_simple_t *simple = &bfd->auth.password;
444
445 fr_assert(session->secret_len <= sizeof(simple->password));
446
447 memcpy(simple->password, session->client.secret, session->secret_len);
448 simple->auth_len = 3 + session->secret_len;
449}
450
451static void bfd_auth_simple(bfd_session_t *session, bfd_packet_t *bfd)
452{
453 bfd_auth_simple_t *simple = &bfd->auth.password;
454
455 simple->auth_type = session->auth_type;
456 simple->auth_len = 3 + session->secret_len;
457 bfd->length = FR_BFD_HEADER_LENGTH + simple->auth_len;
458
459 simple->key_id = 0;
460
461 bfd_calc_simple(session, bfd);
462}
463
464/*
465 * Verify and/or calculate auth-type digests.
466 */
467static void bfd_calc_md5(bfd_session_t *session, bfd_packet_t *bfd)
468{
469 bfd_auth_md5_t *md5 = &bfd->auth.md5;
470
471 fr_assert(session->secret_len <= sizeof(md5->digest));
472 fr_assert(md5->auth_len == sizeof(*md5));
473
474 memset(md5->digest, 0, sizeof(md5->digest));
475 memcpy(md5->digest, session->client.secret, session->secret_len);
476
477 /*
478 * bfd_auth_md5() sets the length, and bfd_verify_md5()
479 * rejects packets with any other length.
480 */
481 fr_assert(bfd->length == (FR_BFD_HEADER_LENGTH + sizeof(*md5)));
482 fr_md5_calc(md5->digest, (const uint8_t *) bfd, FR_BFD_HEADER_LENGTH + sizeof(*md5));
483}
484
485static void bfd_auth_md5(bfd_session_t *session, bfd_packet_t *bfd)
486{
487 bfd_auth_md5_t *md5 = &bfd->auth.md5;
488
489 md5->auth_type = session->auth_type;
490 md5->auth_len = sizeof(*md5);
491 bfd->length = FR_BFD_HEADER_LENGTH + md5->auth_len;
492
493 md5->key_id = 0;
494 md5->sequence_no = session->xmit_auth_seq++;
495
496 bfd_calc_md5(session, bfd);
497}
498
499static void bfd_calc_sha1(bfd_session_t *session, bfd_packet_t *bfd)
500{
501 fr_sha1_ctx ctx;
502 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
503
504 fr_assert(session->secret_len <= sizeof(sha1->digest));
505 fr_assert(sha1->auth_len == sizeof(*sha1));
506
507 memset(sha1->digest, 0, sizeof(sha1->digest));
508 memcpy(sha1->digest, session->client.secret, session->secret_len);
509
510 fr_sha1_init(&ctx);
511 /*
512 * bfd_auth_sha1() sets the length, and bfd_verify_sha1()
513 * rejects packets with any other length.
514 */
515 fr_assert(bfd->length == (FR_BFD_HEADER_LENGTH + sizeof(*sha1)));
516 fr_sha1_update(&ctx, (const uint8_t *) bfd, FR_BFD_HEADER_LENGTH + sizeof(*sha1));
517 fr_sha1_final(sha1->digest, &ctx);
518}
519
520static void bfd_auth_sha1(bfd_session_t *session, bfd_packet_t *bfd)
521{
522 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
523
524 sha1->auth_type = session->auth_type;
525 sha1->auth_len = sizeof(*sha1);
526 bfd->length = FR_BFD_HEADER_LENGTH + sha1->auth_len;
527
528 sha1->key_id = 0;
529 sha1->sequence_no = session->xmit_auth_seq++;
530
531 bfd_calc_sha1(session, bfd);
532}
533
534static int bfd_verify_sequence(bfd_session_t *session, uint32_t sequence_no,
535 int keyed)
536{
537 uint32_t start, stop;
538
539 start = session->recv_auth_seq;
540 if (keyed) {
541 start++;
542 }
543 stop = start + 3 * session->detect_multi;
544
545 if (start < stop) {
546 if ((sequence_no < start) ||
547 (sequence_no > stop)) {
548 return 0;
549 }
550
551 } else { /* start is ~2^32, stop is ~10 */
552 if ((sequence_no < start) &&
553 (sequence_no > stop)) {
554 return 0;
555 }
556 }
557
558 return 1;
559}
560
561static int bfd_verify_simple(bfd_session_t *session, bfd_packet_t *bfd)
562{
563 bfd_auth_simple_t *simple = &bfd->auth.password;
564
565 if ((size_t) simple->auth_len != (3 + session->secret_len)) return 0;
566
567 if (simple->key_id != 0) return 0;
568
569 return (fr_digest_cmp((uint8_t const *) session->client.secret, simple->password, session->secret_len) == 0);
570}
571
572static int bfd_verify_md5(bfd_session_t *session, bfd_packet_t *bfd)
573{
574 int rcode;
575 bfd_auth_md5_t *md5 = &bfd->auth.md5;
576 uint8_t digest[sizeof(md5->digest)];
577
578 if (md5->auth_len != sizeof(*md5)) return 0;
579
580 if (bfd->length != (FR_BFD_HEADER_LENGTH + sizeof(*md5))) return 0;
581
582 if (md5->key_id != 0) return 0;
583
584 memcpy(digest, md5->digest, sizeof(digest));
585
586 bfd_calc_md5(session, bfd);
587 rcode = fr_digest_cmp(digest, md5->digest, sizeof(digest));
588
589 memcpy(md5->digest, digest, sizeof(md5->digest)); /* pedantic */
590
591 if (rcode != 0) {
592 DEBUG("BFD %s peer %s MD5 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****",
593 session->server_name, session->client.shortname);
594 return 0;
595 }
596
597 /*
598 * Do this AFTER the authentication instead of before!
599 */
600 if (!session->auth_seq_known) {
601 session->auth_seq_known = 1;
602
603 } else if (!bfd_verify_sequence(session, md5->sequence_no,
604 (md5->auth_type == BFD_AUTH_MET_KEYED_MD5))) {
605 DEBUG("MD5 sequence out of window");
606 return 0;
607 }
608
609 session->recv_auth_seq = md5->sequence_no;
610
611 return 1;
612}
613
614static int bfd_verify_sha1(bfd_session_t *session, bfd_packet_t *bfd)
615{
616 int rcode;
617 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
618 uint8_t digest[sizeof(sha1->digest)];
619
620 if (sha1->auth_len != sizeof(*sha1)) return 0;
621
622 if (bfd->length != (FR_BFD_HEADER_LENGTH + sizeof(*sha1))) return 0;
623
624 if (sha1->key_id != 0) return 0;
625
626 memcpy(digest, sha1->digest, sizeof(digest));
627
628 bfd_calc_sha1(session, bfd);
629 rcode = fr_digest_cmp(digest, sha1->digest, sizeof(digest));
630
631 memcpy(sha1->digest, digest, sizeof(sha1->digest)); /* pedantic */
632
633 if (rcode != 0) {
634 DEBUG("BFD %s peer %s SHA1 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****",
635 session->server_name, session->client.shortname);
636 return 0;
637 }
638
639 /*
640 * Do this AFTER the authentication instead of before!
641 */
642 if (!session->auth_seq_known) {
643 session->auth_seq_known = 1;
644
645 } else if (!bfd_verify_sequence(session, sha1->sequence_no,
646 (sha1->auth_type == BFD_AUTH_MET_KEYED_SHA1))) {
647 DEBUG("SHA1 sequence out of window");
648 return 0;
649 }
650
651 session->recv_auth_seq = sha1->sequence_no;
652
653 return 1;
654}
655
656static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd)
657{
658 switch (bfd->auth.basic.auth_type) {
660 return 0;
661
662 case BFD_AUTH_SIMPLE:
663 return bfd_verify_simple(session, bfd);
664
667 return bfd_verify_md5(session, bfd);
668
671 return bfd_verify_sha1(session, bfd);
672 }
673
674 return 0;
675}
676
677
678static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd)
679{
680 if (bfd->auth_present) {
681 switch (session->auth_type) {
683 break;
684
685 case BFD_AUTH_SIMPLE:
686 bfd_auth_simple(session, bfd);
687 break;
688
691 bfd_auth_md5(session, bfd);
692 break;
693
696 bfd_auth_sha1(session, bfd);
697 break;
698 }
699 }
700}
701
702
703/*
704 * Initialize a control packet.
705 */
706static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd)
707{
708 memset(bfd, 0, sizeof(*bfd));
709
710 bfd->version = 1;
711 bfd->diag = session->local_diag;
712 bfd->state = session->session_state;
713 bfd->poll = 0; /* fixed by poll response */
714 bfd->final = 0; /* fixed by poll response */
715 bfd->control_plane_independent = 0;
716
717 bfd->auth_present = (session->auth_type != BFD_AUTH_RESERVED);
718
719 /*
720 * If we're UP / UP, signal that we've entered demand
721 * mode, and stop sending packets.
722 */
723 if (session->demand_mode &&
724 (session->session_state == BFD_STATE_UP) &&
725 (session->remote_session_state == BFD_STATE_UP)) {
726 bfd->demand = true;
727
728 DEBUG("BFD %s peer %s demand mode UP / UP, sending ACK and done.",
729 session->server_name, session->client.shortname);
730 bfd_stop_control(session);
731 } else {
732 bfd->demand = false;
733 }
734
735 bfd->multipoint = 0;
736 bfd->detect_multi = session->detect_multi;
737 bfd->length = FR_BFD_HEADER_LENGTH;
738
739 bfd->my_disc = session->local_disc;
740 bfd->your_disc = session->remote_disc;
741
742 bfd->desired_min_tx_interval = fr_time_delta_to_usec(session->desired_min_tx_interval);
743 bfd->required_min_rx_interval = fr_time_delta_to_usec(session->required_min_rx_interval);
744
745 bfd->min_echo_rx_interval = fr_time_delta_to_usec(session->my_min_echo_rx_interval);
746}
747
748static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
749{
750 bfd_control_packet_init(session, bfd);
751
752 bfd->poll = session->doing_poll;
753
754 if (!bfd->demand) {
755 bfd_start_packets(session);
756 }
757
758 bfd_sign(session, bfd);
759}
760
761/*
762 * Send one BFD packet.
763 */
765{
766 bfd_session_t *session = ctx;
767 bfd_packet_t bfd;
768
769 bfd_send_init(session, &bfd);
770
771 DEBUG("BFD %s peer %s sending %s",
772 session->server_name, session->client.shortname, fr_bfd_packet_names[session->session_state]);
773
774 session->last_sent = fr_time();
775
776 if (sendfromto(session->sockfd, &bfd, bfd.length, 0, 0,
777 (struct sockaddr *) &session->local_sockaddr, session->local_salen,
778 (struct sockaddr *) &session->remote_sockaddr, session->remote_salen) < 0) {
779 ERROR("Failed sending packet: %s", fr_syserror(errno));
780 bfd_session_admin_down(session);
781 }
782}
783
784/*
785 * Send one BFD packet.
786 */
788{
789 bfd_session_t *session = ctx;
790 bfd_packet_t *bfd;
791 bfd_wrapper_t *wrapper;
792 fr_io_track_t *track;
794 uint8_t buffer[sizeof(bfd_wrapper_t) + sizeof(*bfd)];
795
796 wrapper = (bfd_wrapper_t *) buffer;
797 bfd = (bfd_packet_t *) wrapper->packet;
798
799 bfd_send_init(session, bfd);
800
801 session->last_sent = fr_time();
802
803 wrapper->type = BFD_WRAPPER_SEND_PACKET;
805 wrapper->session = session;
806
807 parent = talloc_parent(session->listen);
808 (void) talloc_get_type_abort(parent, fr_listen_t);
809
810 track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
811 &session->client.src_ipaddr, session->port);
812 if (!track) return;
813
814 if (unlikely(fr_network_sendto_worker(session->nr, parent, track, (uint8_t const *) wrapper,
815 (wrapper->packet + bfd->length) - (uint8_t *) wrapper, fr_time()) < 0)) {
816 PERROR("Failed sending packet to worker");
817 }
818}
819
820/*
821 * Start sending packets.
822 */
823static void bfd_start_packets(bfd_session_t *session)
824{
825 uint64_t interval, base;
826 uint64_t jitter;
827 fr_timer_cb_t cb;
828
829 /*
830 * Reset the timers.
831 */
832 FR_TIMER_DISARM(session->packet_ev);
833
836 } else {
837 interval = fr_time_delta_unwrap(session->remote_min_rx_interval);
838
839 /*
840 * The other end doesn't want to receive control packets. So we stop sending them.
841 */
842 if (!interval) return;
843 }
844
845 /*
846 * If bfd.DetectMult is equal to 1, the interval between transmitted BFD
847 * Control packets MUST be no more than 90% of the negotiated
848 * transmission interval, and MUST be no less than 75% of the negotiated
849 * transmission interval. This is to ensure that, on the remote system,
850 * the calculated Detection Time does not pass prior to the receipt of
851 * the next BFD Control packet.
852 */
853 base = (interval * 3) / 4;
854 jitter = fr_rand(); /* 32-bit number */
855
856 if (session->detect_multi == 1) {
857 jitter *= 644245094; /* 15% of 2^32 */
858
859 } else {
860 jitter *= (1 << 30); /* 25% of 2^32 */
861 }
862
863 jitter >>= 32;
864 jitter *= interval;
865 jitter >>= 32;
866 interval = base;
867 interval += jitter;
868
869 if (!session->only_state_changes) {
871 } else {
872 cb = bfd_send_packet;
873 }
874
875 if (fr_timer_in(session, session->el->tl, &session->packet_ev,
876 fr_time_delta_wrap(interval),
877 false, cb, session) < 0) {
878 fr_assert("Failed to insert event" == NULL);
879 }
880}
881
882
883/*
884 * Start polling for the peer.
885 */
886static void bfd_start_poll(bfd_session_t *session)
887{
888 if (session->doing_poll) return;
889
890 /*
891 * Already sending packets. Reset the timers and set the
892 * poll bit.
893 */
894 if (!session->remote_demand_mode) {
895 bfd_stop_control(session);
896 }
897
898 session->doing_poll = true;
899
900 /*
901 * Send POLL packets, even if we're not sending CONTROL
902 * packets.
903 */
904 bfd_start_packets(session);
905}
906
907/*
908 * Timer functions
909 */
911{
912 /*
913 * Increasing the value: don't change it if we're already
914 * polling.
915 */
916 if (session->doing_poll &&
917 (session->session_state == BFD_STATE_UP) &&
919 session->next_min_tx_interval = value;
920 return;
921 }
922
923 /*
924 * Don't poll more than once per second.
925 */
926 if (session->session_state != BFD_STATE_UP) {
928 }
929
930 /*
931 * If either bfd.DesiredMinTxInterval is changed or
932 * bfd.RequiredMinRxInterval is changed, a Poll Sequence MUST be
933 * initiated (see section 6.5). If the timing is such that a system
934 * receiving a Poll Sequence wishes to change the parameters described
935 * in this paragraph, the new parameter values MAY be carried in packets
936 * with the Final (F) bit set, even if the Poll Sequence has not yet
937 * been sent.
938 */
939
941
942 /*
943 * Already polling, don't change anything.
944 */
945 if (session->doing_poll) return;
946
947 bfd_stop_control(session);
948 bfd_start_poll(session);
949}
950
951
952/*
953 * We failed to see a packet.
954 */
956{
957 bfd_session_t *session = ctx;
958
959 DEBUG("BFD %s peer %s TIMEOUT state %s",
960 session->server_name, session->client.shortname,
962
963 if (!session->demand_mode) {
964 switch (session->session_state) {
965 case BFD_STATE_INIT:
966 case BFD_STATE_UP:
967 goto start_poll;
968
969 default:
970 break;
971 }
972
973 } else if (!session->doing_poll) {
974 start_poll:
975 DEBUG("BFD %s peer %s State <timeout> -> DOWN (control expired)",
976 session->server_name, session->client.shortname);
977 session->session_state = BFD_STATE_DOWN;
978 session->local_diag = BFD_CTRL_EXPIRED;
980
982 }
983
984 session->remote_disc = 0;
985
986 if (session->detection_timeouts >= 2) {
987 session->auth_seq_known = 0;
988 }
989
990 session->detection_timeouts++;
991
992 bfd_set_timeout(session, now);
993}
994
995/*
996 * Set the timeout for when we've lost enough packets to be
997 * worried.
998 */
999static void bfd_set_timeout(bfd_session_t *session, fr_time_t when)
1000{
1001 fr_time_t timeout;
1002 uint64_t delay;
1003
1004 delay = fr_time_delta_unwrap(session->detection_time);
1005 delay *= session->detect_multi;
1006
1007 delay += fr_time_delta_unwrap(session->detection_time) / 2;
1008
1009 timeout = fr_time_add(when, fr_time_delta_wrap(delay));
1010
1011 if (fr_timer_at(session, session->el->tl, &session->timeout_ev,
1012 timeout, false, bfd_detection_timeout, session) < 0) {
1013 fr_assert("Failed to insert event" == NULL);
1014 }
1015}
1016
1017
1018/*
1019 * Start / stop control packets.
1020 */
1022{
1023 FR_TIMER_DISARM(session->timeout_ev);
1024 FR_TIMER_DISARM(session->packet_ev);
1025 return 1;
1026}
1027
1029{
1030 /*
1031 * @todo - change our discriminator?
1032 */
1033
1034 /*
1035 * We don't expect to see remote packets, so don't do anything.
1036 */
1037 if (fr_time_delta_unwrap(session->remote_min_rx_interval) == 0) return;
1038
1039 /*
1040 * @todo - support passive. From 6.1:
1041 *
1042 * A system may take either an Active role or a Passive role in session
1043 * initialization. A system taking the Active role MUST send BFD
1044 * Control packets for a particular session, regardless of whether it
1045 * has received any BFD packets for that session. A system taking the
1046 * Passive role MUST NOT begin sending BFD packets for a particular
1047 * session until it has received a BFD packet for that session, and thus
1048 * has learned the remote system's discriminator value.
1049 */
1050 if ((session->remote_disc == 0) && session->passive) return;
1051
1052 /*
1053 * We were asked to go "up" when we were already "up"
1054 */
1055 if (session->remote_demand_mode &&
1056 (session->session_state == BFD_STATE_UP) &&
1057 (session->remote_session_state == BFD_STATE_UP) &&
1058 !session->doing_poll) {
1059 DEBUG("BFD %s peer %s warning: asked to start UP / UP ?",
1060 session->server_name, session->client.shortname);
1061 bfd_session_admin_down(session);
1062 return;
1063 }
1064
1065 bfd_set_timeout(session, session->last_recv);
1066
1067 /*
1068 * Start sending packets.
1069 */
1070 bfd_start_packets(session);
1071}
1072
1073
1075{
1076 session->session_state = BFD_STATE_DOWN;
1077 session->local_disc = fr_rand();
1078 session->remote_disc = 0;
1079 session->local_diag = BFD_DIAG_NONE;
1081 session->remote_demand_mode = false;
1082 session->recv_auth_seq = 0;
1083 session->xmit_auth_seq = fr_rand();
1084 session->auth_seq_known = 0;
1085
1086 /*
1087 * Initialize the detection time.
1088 */
1089 if (!session->demand_mode) {
1090 session->detection_time = session->required_min_rx_interval;
1091 } else {
1092 session->detection_time = session->desired_min_tx_interval;
1093 }
1094
1095 return 0;
1096}
1097
1099{
1100 DEBUG("Starting BFD for %s", session->client.shortname);
1101
1102 fr_assert(session->el);
1103
1104 bfd_start_control(session);
1105}
static int const char char buffer[256]
Definition acutest.h:641
@ BFD_CTRL_EXPIRED
Definition bfd.h:42
@ BFD_DIAG_NONE
Definition bfd.h:41
@ BFD_NEIGHBOR_DOWN
Definition bfd.h:44
#define FR_BFD_HEADER_LENGTH
Definition bfd.h:141
@ BFD_AUTH_MET_KEYED_MD5
Definition bfd.h:56
@ BFD_AUTH_MET_KEYED_SHA1
Definition bfd.h:58
@ BFD_AUTH_SIMPLE
Definition bfd.h:54
@ BFD_AUTH_KEYED_SHA1
Definition bfd.h:57
@ BFD_AUTH_KEYED_MD5
Definition bfd.h:55
@ BFD_AUTH_RESERVED
Definition bfd.h:53
bfd_session_state_t
Definition bfd.h:33
@ BFD_STATE_DOWN
Definition bfd.h:35
@ BFD_STATE_INIT
Definition bfd.h:36
@ BFD_STATE_ADMIN_DOWN
Definition bfd.h:34
@ BFD_STATE_UP
Definition bfd.h:37
static bool stop
Definition radmin.c:68
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
Test enumeration values.
Definition dict_test.h:92
int fr_network_sendto_worker(fr_network_t *nr, fr_listen_t *li, void *packet_ctx, uint8_t const *data, size_t data_len, fr_time_t recv_time)
Definition network.c:1116
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition client.h:83
char const * secret
Secret PSK.
Definition client.h:90
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition client.h:84
char const * shortname
Client nickname.
Definition client.h:88
#define PERROR(_fmt,...)
Definition log.h:233
#define fr_time()
Definition event.c:58
static int bfd_verify_simple(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:561
static int bfd_stop_control(bfd_session_t *session)
Definition session.c:1021
static int bfd_stop_poll(bfd_session_t *session)
Definition session.c:87
static void bfd_auth_sha1(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:520
static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:678
static int bfd_verify_md5(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:572
static void bfd_poll_response(bfd_session_t *session)
Definition session.c:125
void bfd_session_start(bfd_session_t *session)
Definition session.c:1098
static void bfd_start_control(bfd_session_t *session)
Definition session.c:1028
static int bfd_verify_sha1(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:614
static void bfd_calc_md5(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:467
static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:656
static void bfd_start_poll(bfd_session_t *session)
Definition session.c:886
static void bfd_calc_simple(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:441
int bfd_session_init(bfd_session_t *session)
Definition session.c:1074
bfd_state_change_t bfd_session_process(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:150
static void bfd_auth_md5(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:485
static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:748
static void bfd_detection_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *ctx)
Definition session.c:955
static void bfd_unlang_send_packet(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition session.c:787
static void bfd_calc_sha1(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:499
static void bfd_trigger(UNUSED bfd_session_t *session, UNUSED bfd_state_change_t change)
Definition session.c:57
static void bfd_send_packet(UNUSED fr_timer_list_t *el, UNUSED fr_time_t now, void *ctx)
Definition session.c:764
static void bfd_start_packets(bfd_session_t *session)
Definition session.c:823
static int bfd_verify_sequence(bfd_session_t *session, uint32_t sequence_no, int keyed)
Definition session.c:534
static void bfd_set_desired_min_tx_interval(bfd_session_t *session, fr_time_delta_t value)
Definition session.c:910
void bfd_session_admin_down(bfd_session_t *session)
Definition session.c:75
static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:706
static void bfd_set_timeout(bfd_session_t *session, fr_time_t when)
Definition session.c:999
static void bfd_auth_simple(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:451
socklen_t local_salen
Definition session.h:52
uint32_t recv_auth_seq
their auth_seq number
Definition session.h:103
int sockfd
cached for laziness
Definition session.h:44
fr_time_delta_t my_min_echo_rx_interval
what we send for echo_rx_interval
Definition session.h:86
fr_timer_t * timeout_ev
when we time out for not receiving a packet
Definition session.h:57
struct sockaddr_storage remote_sockaddr
cached for laziness
Definition session.h:48
size_t secret_len
doesn't change while we're running
Definition session.h:106
bool demand_mode
demand is "once session is up, stop sending packets"
Definition session.h:91
bool doing_poll
Definition session.h:94
bfd_state_change_t
Definition session.h:131
@ BFD_STATE_CHANGE_UP
we are going to UP
Definition session.h:137
@ BFD_STATE_CHANGE_TIMEOUT_DOWN
Definition session.h:138
@ BFD_STATE_CHANGE_INIT
we are going to INIT
Definition session.h:136
@ BFD_STATE_CHANGE_PEER_DOWN
the peer has signalled us that he's Down.
Definition session.h:135
@ BFD_STATE_CHANGE_INVALID
Definition session.h:132
@ BFD_STATE_CHANGE_ADMIN_DOWN
we are admin-down
Definition session.h:134
@ BFD_STATE_CHANGE_NONE
no state change
Definition session.h:133
fr_listen_t * listen
associated listener
Definition session.h:42
bfd_session_state_t remote_session_state
their view of the session state
Definition session.h:64
fr_time_t last_recv
last received packet
Definition session.h:59
fr_time_delta_t required_min_rx_interval
intervals between receives
Definition session.h:82
socklen_t remote_salen
Definition session.h:49
bfd_session_state_t session_state
our view of the session state
Definition session.h:63
uint32_t local_disc
our session ID, which is unique to this session
Definition session.h:74
fr_time_t last_sent
the last time we sent a packet
Definition session.h:61
fr_client_t client
might as well reuse this, others need it
Definition session.h:29
uint32_t remote_disc
their session ID
Definition session.h:75
char const * server_name
our name
Definition session.h:33
bool only_state_changes
copied from proto_bfd_udp.c
Definition session.h:35
fr_timer_t * packet_ev
for when we next send a packet
Definition session.h:58
uint8_t packet[]
Definition session.h:145
uint16_t port
peer port where packets are sent to
Definition session.h:31
bfd_auth_type_t auth_type
what kind of authentication is used
Definition session.h:101
bfd_session_t * session
Definition session.h:144
@ BFD_WRAPPER_STATE_CHANGE
Definition session.h:128
@ BFD_WRAPPER_SEND_PACKET
Definition session.h:127
uint32_t detect_multi
Definition session.h:79
uint32_t xmit_auth_seq
our auth_seq number
Definition session.h:104
bool passive
active or passive role from RFC 5880 - unused
Definition session.h:111
fr_time_delta_t desired_min_tx_interval
intervals between transmits
Definition session.h:81
bool remote_demand_mode
their demand mode
Definition session.h:92
fr_network_t * nr
network side of things
Definition session.h:46
bfd_state_change_t state_change
Definition session.h:143
int detection_timeouts
too many timeouts means !auth_seq_known
Definition session.h:109
struct sockaddr_storage local_sockaddr
cached for laziness
Definition session.h:51
fr_event_list_t * el
event list
Definition session.h:45
fr_time_delta_t next_min_tx_interval
how to update this when we're polling
Definition session.h:88
bool auth_seq_known
do we know the authentication sequence number?
Definition session.h:99
uint32_t type
Definition session.h:142
fr_time_t next_recv
when we next expect to receive a packet
Definition session.h:60
fr_time_delta_t detection_time
used to set ev_timeout
Definition session.h:108
bfd_diag_t local_diag
diagnostics for errors
Definition session.h:77
fr_time_delta_t remote_min_rx_interval
their min_rx_interval
Definition session.h:84
fr_io_track_t * fr_master_io_track_alloc(fr_listen_t *li, fr_client_t *radclient, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
Definition master.c:3585
unsigned int uint32_t
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
unsigned char uint8_t
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition misc.c:516
char const * fr_bfd_packet_names[FR_BFD_CODE_MAX]
Definition base.c:64
#define fr_assert(_expr)
Definition rad_assert.h:37
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:128
void fr_sha1_init(fr_sha1_ctx *context)
Definition sha1.c:93
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
Definition sha1.c:141
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
Definition sha1.c:105
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_lt(_a, _b)
Definition time.h:285
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_wrap(_time)
Definition time.h:152
static int64_t fr_time_delta_to_usec(fr_time_delta_t delta)
Definition time.h:632
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
static fr_cmp_ret_t fr_time_delta_cmp(fr_time_delta_t a, fr_time_delta_t b)
Compare two fr_time_delta_t values.
Definition time.h:930
#define fr_time_gt(_a, _b)
Definition time.h:237
#define USEC
Definition time.h:380
#define fr_time_delta_gteq(_a, _b)
Definition time.h:284
static fr_time_delta_t fr_time_delta_from_usec(int64_t usec)
Definition time.h:568
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:49
#define fr_timer_in(...)
Definition timer.h:87
void(* fr_timer_cb_t)(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Called when a timer event fires.
Definition timer.h:75
#define FR_TIMER_DISARM(_ev)
Definition timer.h:91
#define fr_timer_at(...)
Definition timer.h:81
int sendfromto(int fd, void *buf, size_t len, int flags, int ifindex, struct sockaddr *from, socklen_t from_len, struct sockaddr *to, socklen_t to_len)
Send packet via a file descriptor, setting the src address and outbound interface.
Definition udpfromto.c:421
static fr_event_list_t * el
static fr_slen_t parent
Definition pair.h:864