The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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 
39 static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd);
40 static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd);
41 static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd);
42 
44 
45 static void bfd_start_packets(bfd_session_t *session);
46 static void bfd_start_control(bfd_session_t *session);
47 static int bfd_stop_control(bfd_session_t *session);
48 static 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 
76 {
77  bfd_stop_control(session);
78 
81 }
82 
83 
84 /*
85  * Stop polling for packets.
86  */
87 static 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  */
98  if (fr_time_delta_unwrap(session->next_min_tx_interval) > 0) {
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  */
125 static 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  */
441 static 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 
451 static 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  */
467 static 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 
480 static 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 
494 static 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 
510 static 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 
524 static 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 
551 static 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 
562 static 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 
602 static 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 
642 static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd)
643 {
644  switch (bfd->auth.basic.auth_type) {
645  case BFD_AUTH_RESERVED:
646  return 0;
647 
648  case BFD_AUTH_SIMPLE:
649  return bfd_verify_simple(session, bfd);
650 
651  case BFD_AUTH_KEYED_MD5:
653  return bfd_verify_md5(session, bfd);
654 
655  case BFD_AUTH_KEYED_SHA1:
657  return bfd_verify_sha1(session, bfd);
658  }
659 
660  return 0;
661 }
662 
663 
664 static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd)
665 {
666  if (bfd->auth_present) {
667  switch (session->auth_type) {
668  case BFD_AUTH_RESERVED:
669  break;
670 
671  case BFD_AUTH_SIMPLE:
672  bfd_auth_simple(session, bfd);
673  break;
674 
675  case BFD_AUTH_KEYED_MD5:
677  bfd_auth_md5(session, bfd);
678  break;
679 
680  case BFD_AUTH_KEYED_SHA1:
682  bfd_auth_sha1(session, bfd);
683  break;
684  }
685  }
686 }
687 
688 
689 /*
690  * Initialize a control packet.
691  */
692 static 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 
734 static 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  */
806 static 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  */
817  fr_event_timer_delete(&session->ev_packet);
818 
820  interval = fr_time_delta_unwrap(session->desired_min_tx_interval);
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  */
871 static 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 
925  session->desired_min_tx_interval = value;
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  */
984 static void bfd_set_timeout(bfd_session_t *session, fr_time_t when)
985 {
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  */
1010 static int bfd_stop_control(bfd_session_t *session)
1011 {
1012  fr_event_timer_delete(&session->ev_timeout);
1013  fr_event_timer_delete(&session->ev_packet);
1014  return 1;
1015 }
1016 
1017 static void bfd_start_control(bfd_session_t *session)
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:574
@ 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:313
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
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:1017
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition: client.h:80
char const * secret
Secret PSK.
Definition: client.h:87
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition: client.h:81
char const * shortname
Client nickname.
Definition: client.h:85
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition: event.c:1604
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:3090
unsigned int uint32_t
Definition: merged_model.c:33
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.
Definition: merged_model.c:251
unsigned char uint8_t
Definition: merged_model.c:30
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:463
char const * fr_bfd_packet_names[FR_BFD_CODE_MAX]
Definition: base.c:63
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
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
fr_assert(0)
#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:928
#define fr_time_delta_lt(_a, _b)
Definition: time.h:283
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
#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:630
#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:378
#define fr_time_delta_gteq(_a, _b)
Definition: time.h:282
static fr_time_delta_t fr_time_delta_from_usec(int64_t usec)
Definition: time.h:566
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:844