The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: b0fffb18d2baebee26dbf66490db036767383efb $
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->ev_timeout != NULL);
109 fr_assert(session->ev_packet != 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->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 (bfd->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 fr_md5_calc(md5->digest,(const uint8_t *) bfd, bfd->length);
478}
479
480static void bfd_auth_md5(bfd_session_t *session, bfd_packet_t *bfd)
481{
482 bfd_auth_md5_t *md5 = &bfd->auth.md5;
483
484 md5->auth_type = session->auth_type;
485 md5->auth_len = sizeof(*md5);
486 bfd->length = FR_BFD_HEADER_LENGTH + md5->auth_len;
487
488 md5->key_id = 0;
489 md5->sequence_no = session->xmit_auth_seq++;
490
491 bfd_calc_md5(session, bfd);
492}
493
494static void bfd_calc_sha1(bfd_session_t *session, bfd_packet_t *bfd)
495{
496 fr_sha1_ctx ctx;
497 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
498
499 fr_assert(session->secret_len <= sizeof(sha1->digest));
500 fr_assert(sha1->auth_len == sizeof(*sha1));
501
502 memset(sha1->digest, 0, sizeof(sha1->digest));
503 memcpy(sha1->digest, session->client.secret, session->secret_len);
504
505 fr_sha1_init(&ctx);
506 fr_sha1_update(&ctx, (const uint8_t *) bfd, bfd->length);
507 fr_sha1_final(sha1->digest, &ctx);
508}
509
510static void bfd_auth_sha1(bfd_session_t *session, bfd_packet_t *bfd)
511{
512 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
513
514 sha1->auth_type = session->auth_type;
515 sha1->auth_len = sizeof(*sha1);
516 bfd->length = FR_BFD_HEADER_LENGTH + sha1->auth_len;
517
518 sha1->key_id = 0;
519 sha1->sequence_no = session->xmit_auth_seq++;
520
521 bfd_calc_sha1(session, bfd);
522}
523
524static int bfd_verify_sequence(bfd_session_t *session, uint32_t sequence_no,
525 int keyed)
526{
527 uint32_t start, stop;
528
529 start = session->recv_auth_seq;
530 if (keyed) {
531 start++;
532 }
533 stop = start + 3 * session->detect_multi;
534
535 if (start < stop) {
536 if ((sequence_no < start) ||
537 (sequence_no > stop)) {
538 return 0;
539 }
540
541 } else { /* start is ~2^32, stop is ~10 */
542 if ((sequence_no > start) &&
543 (sequence_no < stop)) {
544 return 0;
545 }
546 }
547
548 return 1;
549}
550
551static int bfd_verify_simple(bfd_session_t *session, bfd_packet_t *bfd)
552{
553 bfd_auth_simple_t *simple = &bfd->auth.password;
554
555 if ((size_t) simple->auth_len != (3 + session->secret_len)) return 0;
556
557 if (simple->key_id != 0) return 0;
558
559 return (fr_digest_cmp((uint8_t const *) session->client.secret, simple->password, session->secret_len) == 0);
560}
561
562static int bfd_verify_md5(bfd_session_t *session, bfd_packet_t *bfd)
563{
564 int rcode;
565 bfd_auth_md5_t *md5 = &bfd->auth.md5;
566 uint8_t digest[sizeof(md5->digest)];
567
568 if (md5->auth_len != sizeof(*md5)) return 0;
569
570 if (md5->key_id != 0) return 0;
571
572 memcpy(digest, md5->digest, sizeof(digest));
573
574 bfd_calc_md5(session, bfd);
575 rcode = fr_digest_cmp(digest, md5->digest, sizeof(digest));
576
577 memcpy(md5->digest, digest, sizeof(md5->digest)); /* pedantic */
578
579 if (rcode != 0) {
580 DEBUG("BFD %s peer %s MD5 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****",
581 session->server_name, session->client.shortname);
582 return 0;
583 }
584
585 /*
586 * Do this AFTER the authentication instead of before!
587 */
588 if (!session->auth_seq_known) {
589 session->auth_seq_known = 1;
590
591 } else if (!bfd_verify_sequence(session, md5->sequence_no,
592 (md5->auth_type == BFD_AUTH_MET_KEYED_MD5))) {
593 DEBUG("MD5 sequence out of window");
594 return 0;
595 }
596
597 session->recv_auth_seq = md5->sequence_no;
598
599 return 1;
600}
601
602static int bfd_verify_sha1(bfd_session_t *session, bfd_packet_t *bfd)
603{
604 int rcode;
605 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
606 uint8_t digest[sizeof(sha1->digest)];
607
608 if (sha1->auth_len != sizeof(*sha1)) return 0;
609
610 if (sha1->key_id != 0) return 0;
611
612 memcpy(digest, sha1->digest, sizeof(digest));
613
614 bfd_calc_sha1(session, bfd);
615 rcode = fr_digest_cmp(digest, sha1->digest, sizeof(digest));
616
617 memcpy(sha1->digest, digest, sizeof(sha1->digest)); /* pedantic */
618
619 if (rcode != 0) {
620 DEBUG("BFD %s peer %s SHA1 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****",
621 session->server_name, session->client.shortname);
622 return 0;
623 }
624
625 /*
626 * Do this AFTER the authentication instead of before!
627 */
628 if (!session->auth_seq_known) {
629 session->auth_seq_known = 1;
630
631 } else if (!bfd_verify_sequence(session, sha1->sequence_no,
632 (sha1->auth_type == BFD_AUTH_MET_KEYED_SHA1))) {
633 DEBUG("SHA1 sequence out of window");
634 return 0;
635 }
636
637 session->recv_auth_seq = sha1->sequence_no;
638
639 return 1;
640}
641
642static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd)
643{
644 switch (bfd->auth.basic.auth_type) {
646 return 0;
647
648 case BFD_AUTH_SIMPLE:
649 return bfd_verify_simple(session, bfd);
650
653 return bfd_verify_md5(session, bfd);
654
657 return bfd_verify_sha1(session, bfd);
658 }
659
660 return 0;
661}
662
663
664static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd)
665{
666 if (bfd->auth_present) {
667 switch (session->auth_type) {
669 break;
670
671 case BFD_AUTH_SIMPLE:
672 bfd_auth_simple(session, bfd);
673 break;
674
677 bfd_auth_md5(session, bfd);
678 break;
679
682 bfd_auth_sha1(session, bfd);
683 break;
684 }
685 }
686}
687
688
689/*
690 * Initialize a control packet.
691 */
692static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd)
693{
694 memset(bfd, 0, sizeof(*bfd));
695
696 bfd->version = 1;
697 bfd->diag = session->local_diag;
698 bfd->state = session->session_state;
699 bfd->poll = 0; /* fixed by poll response */
700 bfd->final = 0; /* fixed by poll response */
701 bfd->control_plane_independent = 0;
702
703 bfd->auth_present = (session->auth_type != BFD_AUTH_RESERVED);
704
705 /*
706 * If we're UP / UP, signal that we've entered demand
707 * mode, and stop sending packets.
708 */
709 if (session->demand_mode &&
710 (session->session_state == BFD_STATE_UP) &&
711 (session->remote_session_state == BFD_STATE_UP)) {
712 bfd->demand = true;
713
714 DEBUG("BFD %s peer %s demand mode UP / UP, sending ACK and done.",
715 session->server_name, session->client.shortname);
716 bfd_stop_control(session);
717 } else {
718 bfd->demand = false;
719 }
720
721 bfd->multipoint = 0;
722 bfd->detect_multi = session->detect_multi;
723 bfd->length = FR_BFD_HEADER_LENGTH;
724
725 bfd->my_disc = session->local_disc;
726 bfd->your_disc = session->remote_disc;
727
728 bfd->desired_min_tx_interval = fr_time_delta_to_usec(session->desired_min_tx_interval);
729 bfd->required_min_rx_interval = fr_time_delta_to_usec(session->required_min_rx_interval);
730
731 bfd->min_echo_rx_interval = fr_time_delta_to_usec(session->my_min_echo_rx_interval);
732}
733
734static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
735{
736 bfd_control_packet_init(session, bfd);
737
738 bfd->poll = session->doing_poll;
739
740 if (!bfd->demand) {
741 bfd_start_packets(session);
742 }
743
744 bfd_sign(session, bfd);
745}
746
747/*
748 * Send one BFD packet.
749 */
751{
752 bfd_session_t *session = ctx;
753 bfd_packet_t bfd;
754
755 bfd_send_init(session, &bfd);
756
757 DEBUG("BFD %s peer %s sending %s",
758 session->server_name, session->client.shortname, fr_bfd_packet_names[session->session_state]);
759
760 session->last_sent = fr_time();
761
762 if (sendfromto(session->sockfd, &bfd, bfd.length, 0, 0,
763 (struct sockaddr *) &session->local_sockaddr, session->local_salen,
764 (struct sockaddr *) &session->remote_sockaddr, session->remote_salen) < 0) {
765 ERROR("Failed sending packet: %s", fr_syserror(errno));
766 bfd_session_admin_down(session);
767 }
768}
769
770/*
771 * Send one BFD packet.
772 */
774{
775 bfd_session_t *session = ctx;
776 bfd_packet_t *bfd;
777 bfd_wrapper_t *wrapper;
778 fr_io_track_t *track;
780 uint8_t buffer[sizeof(bfd_wrapper_t) + sizeof(*bfd)];
781
782 wrapper = (bfd_wrapper_t *) buffer;
783 bfd = (bfd_packet_t *) wrapper->packet;
784
785 bfd_send_init(session, bfd);
786
787 session->last_sent = fr_time();
788
789 wrapper->type = BFD_WRAPPER_SEND_PACKET;
791 wrapper->session = session;
792
793 parent = talloc_parent(session->listen);
794 (void) talloc_get_type_abort(parent, fr_listen_t);
795
796 track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
797 &session->client.src_ipaddr, session->port);
798 if (!track) return;
799
800 (void) fr_network_sendto_worker(session->nr, parent, track, (uint8_t const *) wrapper, (wrapper->packet + bfd->length) - (uint8_t *) wrapper, fr_time());
801}
802
803/*
804 * Start sending packets.
805 */
806static void bfd_start_packets(bfd_session_t *session)
807{
808 uint64_t interval, base;
809 uint64_t jitter;
811
812 if (session->ev_packet) return;
813
814 /*
815 * Reset the timers.
816 */
818
821 } else {
822 interval = fr_time_delta_unwrap(session->remote_min_rx_interval);
823
824 /*
825 * The other end doesn't want to receive control packets. So we stop sending them.
826 */
827 if (!interval) return;
828 }
829
830 /*
831 * If bfd.DetectMult is equal to 1, the interval between transmitted BFD
832 * Control packets MUST be no more than 90% of the negotiated
833 * transmission interval, and MUST be no less than 75% of the negotiated
834 * transmission interval. This is to ensure that, on the remote system,
835 * the calculated Detection Time does not pass prior to the receipt of
836 * the next BFD Control packet.
837 */
838 base = (interval * 3) / 4;
839 jitter = fr_rand(); /* 32-bit number */
840
841 if (session->detect_multi == 1) {
842 jitter *= 644245094; /* 15% of 2^32 */
843
844 } else {
845 jitter *= (1 << 30); /* 25% of 2^32 */
846 }
847
848 jitter >>= 32;
849 jitter *= interval;
850 jitter >>= 32;
851 interval = base;
852 interval += jitter;
853
854 if (!session->only_state_changes) {
856 } else {
857 cb = bfd_send_packet;
858 }
859
860 if (fr_event_timer_in(session, session->el, &session->ev_packet,
861 fr_time_delta_wrap(interval),
862 cb, session) < 0) {
863 fr_assert("Failed to insert event" == NULL);
864 }
865}
866
867
868/*
869 * Start polling for the peer.
870 */
871static void bfd_start_poll(bfd_session_t *session)
872{
873 if (session->doing_poll) return;
874
875 /*
876 * Already sending packets. Reset the timers and set the
877 * poll bit.
878 */
879 if (!session->remote_demand_mode) {
880 bfd_stop_control(session);
881 }
882
883 session->doing_poll = true;
884
885 /*
886 * Send POLL packets, even if we're not sending CONTROL
887 * packets.
888 */
889 bfd_start_packets(session);
890}
891
892/*
893 * Timer functions
894 */
896{
897 /*
898 * Increasing the value: don't change it if we're already
899 * polling.
900 */
901 if (session->doing_poll &&
902 (session->session_state == BFD_STATE_UP) &&
904 session->next_min_tx_interval = value;
905 return;
906 }
907
908 /*
909 * Don't poll more than once per second.
910 */
911 if (session->session_state != BFD_STATE_UP) {
913 }
914
915 /*
916 * If either bfd.DesiredMinTxInterval is changed or
917 * bfd.RequiredMinRxInterval is changed, a Poll Sequence MUST be
918 * initiated (see section 6.5). If the timing is such that a system
919 * receiving a Poll Sequence wishes to change the parameters described
920 * in this paragraph, the new parameter values MAY be carried in packets
921 * with the Final (F) bit set, even if the Poll Sequence has not yet
922 * been sent.
923 */
924
926
927 /*
928 * Already polling, don't change anything.
929 */
930 if (session->doing_poll) return;
931
932 bfd_stop_control(session);
933 bfd_start_poll(session);
934}
935
936
937/*
938 * We failed to see a packet.
939 */
941{
942 bfd_session_t *session = ctx;
943
944 DEBUG("BFD %s peer %s TIMEOUT state %s",
945 session->server_name, session->client.shortname,
947
948 if (!session->demand_mode) {
949 switch (session->session_state) {
950 case BFD_STATE_INIT:
951 case BFD_STATE_UP:
952 goto start_poll;
953
954 default:
955 break;
956 }
957
958 } else if (!session->doing_poll) {
959 start_poll:
960 DEBUG("BFD %s peer %s State <timeout> -> DOWN (control expired)",
961 session->server_name, session->client.shortname);
962 session->session_state = BFD_STATE_DOWN;
963 session->local_diag = BFD_CTRL_EXPIRED;
965
967 }
968
969 session->remote_disc = 0;
970
971 if (session->detection_timeouts >= 2) {
972 session->auth_seq_known = 0;
973 }
974
975 session->detection_timeouts++;
976
977 bfd_set_timeout(session, now);
978}
979
980/*
981 * Set the timeout for when we've lost enough packets to be
982 * worried.
983 */
984static void bfd_set_timeout(bfd_session_t *session, fr_time_t when)
985{
986 fr_time_t timeout;
987 uint64_t delay;
988 fr_time_delta_t delta;
989
991
992 delay = fr_time_delta_unwrap(session->detection_time);
993 delay *= session->detect_multi;
994
995 delay += fr_time_delta_unwrap(session->detection_time) / 2;
996 delta = fr_time_delta_from_usec(delay);
997
998 timeout = fr_time_add(when, delta);
999
1000 if (fr_event_timer_at(session, session->el, &session->ev_timeout,
1001 timeout, bfd_detection_timeout, session) < 0) {
1002 fr_assert("Failed to insert event" == NULL);
1003 }
1004}
1005
1006
1007/*
1008 * Start / stop control packets.
1009 */
1011{
1014 return 1;
1015}
1016
1018{
1019 /*
1020 * @todo - change our discriminator?
1021 */
1022
1023 /*
1024 * We don't expect to see remote packets, so don't do anything.
1025 */
1026 if (fr_time_delta_unwrap(session->remote_min_rx_interval) == 0) return;
1027
1028 /*
1029 * @todo - support passive. From 6.1:
1030 *
1031 * A system may take either an Active role or a Passive role in session
1032 * initialization. A system taking the Active role MUST send BFD
1033 * Control packets for a particular session, regardless of whether it
1034 * has received any BFD packets for that session. A system taking the
1035 * Passive role MUST NOT begin sending BFD packets for a particular
1036 * session until it has received a BFD packet for that session, and thus
1037 * has learned the remote system's discriminator value.
1038 */
1039 if ((session->remote_disc == 0) && session->passive) return;
1040
1041 /*
1042 * We were asked to go "up" when we were already "up"
1043 */
1044 if (session->remote_demand_mode &&
1045 (session->session_state == BFD_STATE_UP) &&
1046 (session->remote_session_state == BFD_STATE_UP) &&
1047 !session->doing_poll) {
1048 DEBUG("BFD %s peer %s warning: asked to start UP / UP ?",
1049 session->server_name, session->client.shortname);
1050 bfd_session_admin_down(session);
1051 return;
1052 }
1053
1054 bfd_set_timeout(session, session->last_recv);
1055
1056 /*
1057 * Start sending packets.
1058 */
1059 bfd_start_packets(session);
1060}
1061
1062
1064{
1065 session->session_state = BFD_STATE_DOWN;
1066 session->local_disc = fr_rand();
1067 session->remote_disc = 0;
1068 session->local_diag = BFD_DIAG_NONE;
1070 session->remote_demand_mode = false;
1071 session->recv_auth_seq = 0;
1072 session->xmit_auth_seq = fr_rand();
1073 session->auth_seq_known = 0;
1074
1075 /*
1076 * Initialize the detection time.
1077 */
1078 if (!session->demand_mode) {
1079 session->detection_time = session->required_min_rx_interval;
1080 } else {
1081 session->detection_time = session->desired_min_tx_interval;
1082 }
1083
1084 return 0;
1085}
1086
1088{
1089 DEBUG("Starting BFD for %s", session->client.shortname);
1090
1091 fr_assert(session->el);
1092
1093 bfd_start_control(session);
1094}
static int const char char buffer[256]
Definition acutest.h:576
@ 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
#define FR_BFD_HEADER_LENGTH
Definition bfd.h:141
@ BFD_CTRL_EXPIRED
Definition bfd.h:42
@ BFD_DIAG_NONE
Definition bfd.h:41
@ BFD_NEIGHBOR_DOWN
Definition bfd.h:44
@ 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:70
#define UNUSED
Definition build.h:315
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
Test enumeration values.
Definition dict_test.h:92
void(* fr_event_timer_cb_t)(fr_event_list_t *el, fr_time_t now, void *uctx)
Called when a timer event fires.
Definition event.h:118
#define fr_event_timer_at(...)
Definition event.h:250
#define fr_event_timer_in(...)
Definition event.h:255
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:1030
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
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition event.c:1611
Stores all information relating to an event list.
Definition event.c:411
static int bfd_verify_simple(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:551
static int bfd_stop_control(bfd_session_t *session)
Definition session.c:1010
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:510
static void bfd_unlang_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
Definition session.c:773
static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:664
static int bfd_verify_md5(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:562
static void bfd_poll_response(bfd_session_t *session)
Definition session.c:125
void bfd_session_start(bfd_session_t *session)
Definition session.c:1087
static void bfd_start_control(bfd_session_t *session)
Definition session.c:1017
static int bfd_verify_sha1(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:602
static void bfd_calc_md5(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:467
static void bfd_detection_timeout(UNUSED fr_event_list_t *el, fr_time_t now, void *ctx)
Definition session.c:940
static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:642
static void bfd_start_poll(bfd_session_t *session)
Definition session.c:871
static void bfd_calc_simple(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:441
static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
Definition session.c:750
int bfd_session_init(bfd_session_t *session)
Definition session.c:1063
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:480
static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:734
static void bfd_calc_sha1(bfd_session_t *session, bfd_packet_t *bfd)
Definition session.c:494
static void bfd_trigger(UNUSED bfd_session_t *session, UNUSED bfd_state_change_t change)
Definition session.c:57
static void bfd_start_packets(bfd_session_t *session)
Definition session.c:806
static int bfd_verify_sequence(bfd_session_t *session, uint32_t sequence_no, int keyed)
Definition session.c:524
static void bfd_set_desired_min_tx_interval(bfd_session_t *session, fr_time_delta_t value)
Definition session.c:895
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:692
static void bfd_set_timeout(bfd_session_t *session, fr_time_t when)
Definition session.c:984
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
struct sockaddr_storage remote_sockaddr
cached for laziness
Definition session.h:48
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
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
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
@ BFD_WRAPPER_STATE_CHANGE
Definition session.h:128
@ BFD_WRAPPER_SEND_PACKET
Definition session.h:127
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
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
fr_event_timer_t const * ev_timeout
when we time out for not receiving a packet
Definition session.h:57
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_event_timer_t const * ev_packet
for when we next send a packet
Definition session.h:58
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:3093
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:472
char const * fr_bfd_packet_names[FR_BFD_CODE_MAX]
Definition base.c:63
#define fr_assert(_expr)
Definition rad_assert.h:38
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
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
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
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
static int8_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_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
#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
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:391
static fr_event_list_t * el
static fr_slen_t parent
Definition pair.h:851