26 #include <freeradius-devel/util/debug.h>
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>
68 &session->client.src_ipaddr, session->port);
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",
170 if (bfd->auth_present &&
172 DEBUG(
"BFD %s peer %s packet asked to authenticate an unauthenticated session.",
181 if (!bfd->auth_present &&
183 DEBUG(
"BFD %s peer %s packet failed to authenticate an authenticated session.",
194 DEBUG(
"BFD %s peer %s authentication failed for packet",
216 if ((bfd->required_min_rx_interval > 32) && (bfd->required_min_rx_interval <
USEC)) {
224 if (bfd->min_echo_rx_interval == 0) {
231 bfd_stop_echo(session);
271 DEBUG(
"Discarding BFD packet (admin down)");
286 DEBUG(
"BFD %s peer %s State %s -> DOWN (neighbour %s)",
297 switch (bfd->state) {
299 DEBUG(
"BFD %s peer %s State DOWN -> INIT (neighbor DOWN)",
306 DEBUG(
"BFD %s peer %s State DOWN -> UP (neighbor INIT)",
318 switch (bfd->state) {
321 DEBUG(
"BFD %s peer %s State INIT -> UP",
333 switch (bfd->state) {
343 DEBUG(
"Internal sanity check failed");
372 DEBUG(
"BFD %s peer %s demand mode UP / UP, stopping packets",
443 bfd_auth_simple_t *simple = &bfd->auth.password;
453 bfd_auth_simple_t *simple = &bfd->auth.password;
469 bfd_auth_md5_t *md5 = &bfd->auth.md5;
472 fr_assert(md5->auth_len ==
sizeof(*md5));
474 memset(md5->digest, 0,
sizeof(md5->digest));
482 bfd_auth_md5_t *md5 = &bfd->auth.md5;
485 md5->auth_len =
sizeof(*md5);
497 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
500 fr_assert(sha1->auth_len ==
sizeof(*sha1));
502 memset(sha1->digest, 0,
sizeof(sha1->digest));
512 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
515 sha1->auth_len =
sizeof(*sha1);
536 if ((sequence_no < start) ||
537 (sequence_no >
stop)) {
542 if ((sequence_no > start) &&
543 (sequence_no <
stop)) {
553 bfd_auth_simple_t *simple = &bfd->auth.password;
555 if ((
size_t) simple->auth_len != (3 + session->
secret_len))
return 0;
557 if (simple->key_id != 0)
return 0;
565 bfd_auth_md5_t *md5 = &bfd->auth.md5;
566 uint8_t digest[
sizeof(md5->digest)];
568 if (md5->auth_len !=
sizeof(*md5))
return 0;
570 if (md5->key_id != 0)
return 0;
572 memcpy(digest, md5->digest,
sizeof(digest));
577 memcpy(md5->digest, digest,
sizeof(md5->digest));
580 DEBUG(
"BFD %s peer %s MD5 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****",
593 DEBUG(
"MD5 sequence out of window");
605 bfd_auth_sha1_t *sha1 = &bfd->auth.sha1;
606 uint8_t digest[
sizeof(sha1->digest)];
608 if (sha1->auth_len !=
sizeof(*sha1))
return 0;
610 if (sha1->key_id != 0)
return 0;
612 memcpy(digest, sha1->digest,
sizeof(digest));
617 memcpy(sha1->digest, digest,
sizeof(sha1->digest));
620 DEBUG(
"BFD %s peer %s SHA1 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****",
633 DEBUG(
"SHA1 sequence out of window");
644 switch (bfd->auth.basic.auth_type) {
666 if (bfd->auth_present) {
694 memset(bfd, 0,
sizeof(*bfd));
701 bfd->control_plane_independent = 0;
714 DEBUG(
"BFD %s peer %s demand mode UP / UP, sending ACK and done.",
757 DEBUG(
"BFD %s peer %s sending %s",
783 bfd = (bfd_packet_t *) wrapper->
packet;
808 uint64_t interval, base;
827 if (!interval)
return;
838 base = (interval * 3) / 4;
863 fr_assert(
"Failed to insert event" == NULL);
944 DEBUG(
"BFD %s peer %s TIMEOUT state %s",
960 DEBUG(
"BFD %s peer %s State <timeout> -> DOWN (control expired)",
1002 fr_assert(
"Failed to insert event" == NULL);
1048 DEBUG(
"BFD %s peer %s warning: asked to start UP / UP ?",
static int const char char buffer[256]
@ BFD_AUTH_MET_KEYED_SHA1
#define FR_BFD_HEADER_LENGTH
static fr_time_delta_t timeout
void(* fr_event_timer_cb_t)(fr_event_list_t *el, fr_time_t now, void *uctx)
Called when a timer event fires.
#define fr_event_timer_at(...)
#define fr_event_timer_in(...)
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)
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
char const * secret
Secret PSK.
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
char const * shortname
Client nickname.
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Stores all information relating to an event list.
static int bfd_verify_simple(bfd_session_t *session, bfd_packet_t *bfd)
static int bfd_stop_control(bfd_session_t *session)
static int bfd_stop_poll(bfd_session_t *session)
static void bfd_auth_sha1(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_unlang_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd)
static int bfd_verify_md5(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_poll_response(bfd_session_t *session)
void bfd_session_start(bfd_session_t *session)
static void bfd_start_control(bfd_session_t *session)
static int bfd_verify_sha1(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_calc_md5(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_detection_timeout(UNUSED fr_event_list_t *el, fr_time_t now, void *ctx)
static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_start_poll(bfd_session_t *session)
static void bfd_calc_simple(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
int bfd_session_init(bfd_session_t *session)
bfd_state_change_t bfd_session_process(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_auth_md5(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_calc_sha1(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_trigger(UNUSED bfd_session_t *session, UNUSED bfd_state_change_t change)
static void bfd_start_packets(bfd_session_t *session)
static int bfd_verify_sequence(bfd_session_t *session, uint32_t sequence_no, int keyed)
static void bfd_set_desired_min_tx_interval(bfd_session_t *session, fr_time_delta_t value)
void bfd_session_admin_down(bfd_session_t *session)
static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd)
static void bfd_set_timeout(bfd_session_t *session, fr_time_t when)
static void bfd_auth_simple(bfd_session_t *session, bfd_packet_t *bfd)
uint32_t recv_auth_seq
their auth_seq number
int sockfd
cached for laziness
fr_time_delta_t my_min_echo_rx_interval
what we send for echo_rx_interval
struct sockaddr_storage remote_sockaddr
cached for laziness
@ BFD_STATE_CHANGE_UP
we are going to UP
@ BFD_STATE_CHANGE_TIMEOUT_DOWN
@ BFD_STATE_CHANGE_INIT
we are going to INIT
@ BFD_STATE_CHANGE_PEER_DOWN
the peer has signalled us that he's Down.
@ BFD_STATE_CHANGE_INVALID
@ BFD_STATE_CHANGE_ADMIN_DOWN
we are admin-down
@ BFD_STATE_CHANGE_NONE
no state change
size_t secret_len
doesn't change while we're running
bool demand_mode
demand is "once session is up, stop sending packets"
fr_listen_t * listen
associated listener
bfd_session_state_t remote_session_state
their view of the session state
fr_time_t last_recv
last received packet
fr_time_delta_t required_min_rx_interval
intervals between receives
bfd_session_state_t session_state
our view of the session state
uint32_t local_disc
our session ID, which is unique to this session
@ BFD_WRAPPER_STATE_CHANGE
@ BFD_WRAPPER_SEND_PACKET
fr_time_t last_sent
the last time we sent a packet
fr_client_t client
might as well reuse this, others need it
uint32_t remote_disc
their session ID
char const * server_name
our name
bool only_state_changes
copied from proto_bfd_udp.c
uint16_t port
peer port where packets are sent to
bfd_auth_type_t auth_type
what kind of authentication is used
fr_event_timer_t const * ev_timeout
when we time out for not receiving a packet
uint32_t xmit_auth_seq
our auth_seq number
bool passive
active or passive role from RFC 5880 - unused
fr_time_delta_t desired_min_tx_interval
intervals between transmits
bool remote_demand_mode
their demand mode
fr_network_t * nr
network side of things
bfd_state_change_t state_change
int detection_timeouts
too many timeouts means !auth_seq_known
struct sockaddr_storage local_sockaddr
cached for laziness
fr_event_list_t * el
event list
fr_time_delta_t next_min_tx_interval
how to update this when we're polling
bool auth_seq_known
do we know the authentication sequence number?
fr_time_t next_recv
when we next expect to receive a packet
fr_time_delta_t detection_time
used to set ev_timeout
bfd_diag_t local_diag
diagnostics for errors
fr_event_timer_t const * ev_packet
for when we next send a packet
fr_time_delta_t remote_min_rx_interval
their min_rx_interval
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)
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.
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.
char const * fr_bfd_packet_names[FR_BFD_CODE_MAX]
uint32_t fr_rand(void)
Return a 32-bit random number.
void fr_sha1_init(fr_sha1_ctx *context)
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
static int8_t fr_time_delta_cmp(fr_time_delta_t a, fr_time_delta_t b)
Compare two fr_time_delta_t values.
#define fr_time_delta_lt(_a, _b)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_delta_wrap(_time)
static int64_t fr_time_delta_to_usec(fr_time_delta_t delta)
#define fr_time_add(_a, _b)
Add a time/time delta together.
#define fr_time_gt(_a, _b)
#define fr_time_delta_gteq(_a, _b)
static fr_time_delta_t fr_time_delta_from_usec(int64_t usec)
A time delta, a difference in time measured in nanoseconds.
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.
static fr_event_list_t * el