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;
 
  802                PERROR(
"Failed sending packet to worker");
 
 
  811        uint64_t        interval, base;
 
  828                if (!interval) 
return;
 
  839        base = (interval * 3) / 4;
 
  863                        false, cb, session) < 0) {
 
  864                fr_assert(
"Failed to insert event" == NULL);
 
 
  945        DEBUG(
"BFD %s peer %s TIMEOUT state %s",
 
  961                DEBUG(
"BFD %s peer %s State <timeout> -> DOWN (control expired)",
 
 
 1001                fr_assert(
"Failed to insert event" == NULL);
 
 
 1047                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
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.
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_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 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)
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_detection_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *ctx)
static void bfd_unlang_send_packet(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
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_send_packet(UNUSED fr_timer_list_t *el, UNUSED fr_time_t now, void *ctx)
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
fr_timer_t * timeout_ev
when we time out for not receiving a packet
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
fr_timer_t * packet_ev
for when we next send a packet
uint16_t port
peer port where packets are sent to
bfd_auth_type_t auth_type
what kind of authentication is used
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_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.
void(* fr_timer_cb_t)(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Called when a timer event fires.
#define FR_TIMER_DISARM(_ev)
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