From: Alan T. DeKok Date: Fri, 10 Mar 2023 15:24:36 +0000 (-0500) Subject: this code is no longer necessary X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b03739b11fb064a80ea3d3191f4b2b07791801ab;p=thirdparty%2Ffreeradius-server.git this code is no longer necessary all of the relevant work has been ported to the new framework. --- diff --git a/src/modules/proto_bfd/README.md b/src/modules/proto_bfd/README.md deleted file mode 100644 index 89d3a7a0436..00000000000 --- a/src/modules/proto_bfd/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# proto_bfd -## Metadata -
-
category
protocols
-
- -## Summary -Implements BiDirectional Forwarding Protocol (RFC 5880) - allowing the server to quickly detect if a link is up or down. -This module can be used to detect if a *peer* application is up or down and use the trigger module to execute certain functions when the link is started, goes up, down, or is administratively down. - diff --git a/src/modules/proto_bfd/proto_bfd.c b/src/modules/proto_bfd/proto_bfd.c deleted file mode 100644 index 290904a733c..00000000000 --- a/src/modules/proto_bfd/proto_bfd.c +++ /dev/null @@ -1,1865 +0,0 @@ -/* - * proto_bfd.c BFD processing. - * - * Version: $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * @copyright 2012 Network RADIUS SAS (legal@networkradius.com) - * - * Check on RFC 5881 for BFD over IP issues. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define BFD_MAX_SECRET_LENGTH 20 - -typedef enum bfd_session_state_t { - BFD_STATE_ADMIN_DOWN = 0, - BFD_STATE_DOWN, - BFD_STATE_INIT, - BFD_STATE_UP -} bfd_session_state_t; - -typedef enum bfd_diag_t { - BFD_DIAG_NONE = 0, - BFD_CTRL_EXPIRED, - BFD_ECHO_FAILED, - BFD_NEIGHBOR_DOWN, - BFD_FORWARD_PLANE_RESET, - BFD_PATH_DOWN, - BFD_CONCATENATED_PATH_DOWN, - BFD_ADMIN_DOWN, - BFD_REVERSE_CONCAT_PATH_DOWN -} bfd_diag_t; - -typedef enum bfd_auth_type_t { - BFD_AUTH_RESERVED = 0, - BFD_AUTH_SIMPLE, - BFD_AUTH_KEYED_MD5, - BFD_AUTH_MET_KEYED_MD5, - BFD_AUTH_KEYED_SHA1, - BFD_AUTH_MET_KEYED_SHA1, -} bfd_auth_type_t; - -#define BFD_AUTH_INVALID (BFD_AUTH_MET_KEYED_SHA1 + 1) - -typedef struct { - fr_rb_node_t node; //!< Entry in the tree of sessions. - - int number; - - fr_socket_t socket; - - fr_event_list_t *el; - CONF_SECTION *server_cs; - CONF_SECTION *unlang; - - bool blocked; - int pipefd[2]; - pthread_t pthread_id; - - bfd_auth_type_t auth_type; - uint8_t secret[BFD_MAX_SECRET_LENGTH]; - size_t secret_len; - - /* - * To simplify sending the packets. - */ - struct sockaddr_storage remote_sockaddr; - socklen_t salen; - - fr_event_timer_t const *ev_timeout; - fr_event_timer_t const *ev_packet; - fr_time_t last_recv; - fr_time_t next_recv; - fr_time_t last_sent; - - bfd_session_state_t session_state; - bfd_session_state_t remote_session_state; - - uint32_t local_disc; - uint32_t remote_disc; - - bfd_diag_t local_diag; - - uint32_t desired_min_tx_interval; /* in usec */ - uint32_t required_min_rx_interval; - uint32_t remote_min_rx_interval; - uint32_t remote_min_echo_rx_interval; - - uint32_t next_min_tx_interval; - - bool demand_mode; - bool remote_demand_mode; - - int detect_multi; - - uint32_t recv_auth_seq; - uint32_t xmit_auth_seq; - - int auth_seq_known; - - int doing_poll; - uint32_t my_min_echo_rx_interval; - - uint32_t detection_time; - int detection_timeouts; - - int passive; -} bfd_state_t; - -typedef struct { - uint8_t auth_type; - uint8_t auth_len; - uint8_t key_id; -} __attribute__ ((packed)) bfd_auth_basic_t; - - -typedef struct { - uint8_t auth_type; - uint8_t auth_len; - uint8_t key_id; - uint8_t password[16]; -} __attribute__ ((packed)) bfd_auth_simple_t; - -typedef struct { - uint8_t auth_type; - uint8_t auth_len; - uint8_t key_id; - uint8_t reserved; - uint32_t sequence_no; - uint8_t digest[MD5_DIGEST_LENGTH]; -} __attribute__ ((packed)) bfd_auth_md5_t; - -typedef struct { - uint8_t auth_type; - uint8_t auth_len; - uint8_t key_id; - uint8_t reserved; - uint32_t sequence_no; - uint8_t digest[SHA1_DIGEST_LENGTH]; -} __attribute__ ((packed)) bfd_auth_sha1_t; - -typedef union bfd_auth_t { - bfd_auth_basic_t basic; - bfd_auth_simple_t password; - bfd_auth_md5_t md5; - bfd_auth_sha1_t sha1; -} __attribute__ ((packed)) bfd_auth_t; - - -/* - * A packet - */ -typedef struct { -#ifdef WORDS_BIGENDIAN - unsigned int version : 3; - unsigned int diag : 5; - unsigned int state : 2; - unsigned int poll : 1; - unsigned int final : 1; - unsigned int control_plane_independent : 1; - unsigned int auth_present : 1; - unsigned int demand : 1; - unsigned int multipoint : 1; -#else - unsigned int diag : 5; - unsigned int version : 3; - - unsigned int multipoint : 1; - unsigned int demand : 1; - unsigned int auth_present : 1; - unsigned int control_plane_independent : 1; - unsigned int final : 1; - unsigned int poll : 1; - unsigned int state : 2; -#endif - uint8_t detect_multi; - uint8_t length; - uint32_t my_disc; - uint32_t your_disc; - uint32_t desired_min_tx_interval; - uint32_t required_min_rx_interval; - uint32_t min_echo_rx_interval; - bfd_auth_t auth; -} __attribute__ ((packed)) bfd_packet_t; - - -typedef struct { - fr_ipaddr_t my_ipaddr; - uint16_t my_port; - - char const *interface; - - int number; - CONF_SECTION *server_cs; - CONF_SECTION *unlang; - - uint32_t min_tx_interval; - uint32_t min_rx_interval; - uint32_t max_timeouts; - bool demand; - - bfd_auth_type_t auth_type; - uint8_t secret[BFD_MAX_SECRET_LENGTH]; - size_t secret_len; - - fr_rb_tree_t *session_tree; -} bfd_socket_t; - -static fr_dict_t const *dict_bfd; - -extern fr_dict_autoload_t proto_bfd_dict[]; -fr_dict_autoload_t proto_bfd_dict[] = { - { .out = &dict_bfd, .proto = "bfd" }, - { NULL } -}; - -static int bfd_start_packets(bfd_state_t *session); -static int bfd_start_control(bfd_state_t *session); -static int bfd_stop_control(bfd_state_t *session); -static void bfd_detection_timeout(UNUSED fr_event_list_t *eel, fr_time_t now, void *ctx); -static int bfd_process(bfd_state_t *session, bfd_packet_t *bfd); - -static fr_event_list_t *event_list = NULL; /* don't ask */ - -void bfd_init(fr_event_list_t *xel); - -void bfd_init(fr_event_list_t *xel) -{ - event_list = xel; -} - -static void bfd_pthread_free(bfd_state_t *session) -{ - session->blocked = true; - - close(session->pipefd[0]); - close(session->pipefd[1]); - - talloc_free(session->el); - - session->el = NULL; - session->pipefd[0] = session->pipefd[1] = -1; - - session->blocked = false; -} - -/* - * A child thread reads the packet from a pipe, and processes it. - */ -static void bfd_pipe_recv(UNUSED fr_event_list_t *xel, int fd, UNUSED int flags, void *ctx) -{ - ssize_t num; - bfd_state_t *session = ctx; - bfd_packet_t bfd; - - if (session->blocked) return; - - /* - * Read the header - */ - num = read(fd, &bfd, 4); - if ((num < 4) || (bfd.length < 4)) { - fail: - ERROR("BFD Failed reading from pipe!"); - session->blocked = true; - return; - } - - /* - * This is already checked in the caller, but what the heck... - */ - if (bfd.length > sizeof(bfd)) goto fail; - - /* - * Read the rest of the packet. - */ - num = read(fd, ((uint8_t *) &bfd) + 4, bfd.length - 4); - if ((num < 0) || ((num + 4) != bfd.length)) goto fail; - - bfd_process(session, &bfd); -} - -/* - * Do nothing more than read from the sockets and process the - * timers. - */ -static void *bfd_child_thread(void *ctx) -{ - bfd_state_t *session = ctx; - - DEBUG("BFD %d starting child thread", session->number); - bfd_start_control(session); - - fr_event_loop(session->el); - - bfd_pthread_free(session); - - return NULL; -} - - -static int bfd_pthread_create(bfd_state_t *session) -{ - pthread_attr_t attr; - - if (pipe(session->pipefd) < 0) { - ERROR("Failed opening pipe: %s", fr_syserror(errno)); - return 0; - } - - session->el = fr_event_list_alloc(session, NULL, NULL); - if (!session->el) { - ERROR("Failed creating event list"); - close_pipes: - close(session->pipefd[0]); - close(session->pipefd[1]); - session->pipefd[0] = session->pipefd[1] = -1; - return 0; - } - -#ifdef O_NONBLOCK - fcntl(session->pipefd[0], F_SETFL, O_NONBLOCK | FD_CLOEXEC); - fcntl(session->pipefd[1], F_SETFL, O_NONBLOCK | FD_CLOEXEC); -#endif - - if (fr_event_fd_insert(session, session->el, session->pipefd[0], - bfd_pipe_recv, - NULL, - NULL, - session) < 0) { - PERROR("Failed inserting file descriptor into event list"); - goto close_pipes; - } - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - /* - * Create the thread detached, so that it cleans up it's - * own memory when it exits. - * - * Note that the function returns non-zero on error, NOT - * -1. The return code is the error, and errno isn't set. - */ - if (fr_schedule_pthread_create(&session->pthread_id, bfd_child_thread, session) < 0) { - talloc_free(session->el); - session->el = NULL; - PERROR("Thread create failed"); - goto close_pipes; - } - pthread_attr_destroy(&attr); - - return 1; -} - -static const char *bfd_state[] = { - "admin-down", - "down", - "init", - "up" -}; - - -static void bfd_request(bfd_state_t *session, request_t *request, fr_radius_packet_t *packet) -{ - memset(packet, 0, sizeof(*packet)); - - request->packet = packet; - packet->socket = session->socket; - /* request->heap_offset = -1; */ -} - - -static void bfd_trigger(bfd_state_t *session) -{ - fr_radius_packet_t packet; - request_t *request = request_local_alloc_external(session, NULL); - char buffer[256]; - - snprintf(buffer, sizeof(buffer), "server.bfd.%s", - bfd_state[session->session_state]); - - bfd_request(session, request, &packet); - - trigger_exec(unlang_interpret_get_thread_default(), NULL, buffer, false, NULL); -} - - -static void bfd_session_free(void *ctx) -{ - bfd_state_t *session = ctx; - - if (event_list != session->el) { - /* - * FIXME: this isn't particularly safe. - */ - bfd_pthread_free(session); - } - - talloc_free(session); -} - - -static ssize_t bfd_parse_secret(CONF_SECTION *cs, uint8_t secret[BFD_MAX_SECRET_LENGTH]) -{ - int rcode; - size_t len; - char const *value = NULL; - - rcode = cf_pair_parse(NULL, cs, "secret", FR_ITEM_POINTER(FR_TYPE_STRING, &value), NULL, T_INVALID); - if (rcode != 0) return 0; - - len = strlen(value); - - if ((value[0] == '0') && (value[1] == 'x')) { - if (len > 42) { - cf_log_err(cf_section_to_item(cs), "Secret is too long"); - return -1; - } - - if ((len & 0x01) != 0) { - cf_log_err(cf_section_to_item(cs), "Invalid hex length"); - return -1; - } - - return fr_base16_decode(NULL, &FR_DBUFF_TMP(secret, BFD_MAX_SECRET_LENGTH), - &FR_SBUFF_IN(value + 2, (len - 2)), false); - } - - if (len >= 20) { - cf_log_err(cf_section_to_item(cs), "Secret is too long"); - return -1; - } - - memset(secret, 0, BFD_MAX_SECRET_LENGTH); - memcpy(secret, value, len); - return len; -} - - - -/* - * Create a new session. - */ -static bfd_state_t *bfd_new_session(bfd_socket_t *sock, int sockfd, - CONF_SECTION *cs, - const fr_ipaddr_t *ipaddr, uint16_t port) -{ - int rcode; - bool flag; - bfd_state_t *session; - - session = talloc_zero(sock, bfd_state_t); - - /* - * Initialize according to RFC. - */ - session->number = sock->number++; - session->socket.fd = sockfd; - session->session_state = BFD_STATE_DOWN; - session->server_cs = sock->server_cs; - session->unlang = sock->unlang; - session->local_disc = fr_rand(); - session->remote_disc = 0; - session->local_diag = BFD_DIAG_NONE; - session->desired_min_tx_interval = sock->min_tx_interval * 1000; - session->required_min_rx_interval = sock->min_rx_interval * 1000; - session->remote_min_rx_interval = 1; - session->demand_mode = sock->demand; - session->remote_demand_mode = false; - session->detect_multi = sock->max_timeouts; - session->auth_type = BFD_AUTH_RESERVED; - session->recv_auth_seq = 0; - session->xmit_auth_seq = fr_rand(); - session->auth_seq_known = 0; - - /* - * Allow over-riding of variables per session. - */ - rcode = cf_pair_parse(NULL, cs, "demand", FR_ITEM_POINTER(FR_TYPE_BOOL, &flag), NULL, T_INVALID); - if (rcode == 0) { - session->demand_mode = flag; - } - - /* - * Number is moved out of scope to shut up lgtm - * static analysis, but really these should be - * moved into conf_parser callback functions. - */ - { - uint32_t number; - - rcode = cf_pair_parse(NULL, cs, "min_transmit_interval", FR_ITEM_POINTER(FR_TYPE_UINT32, &number), NULL, T_INVALID); - if (rcode == 0) { - if (number < 100) number = 100; - if (number > 10000) number = 10000; - - session->desired_min_tx_interval = number * 1000; - } - } - - { - uint32_t number; - - rcode = cf_pair_parse(NULL, cs, "min_receive_interval", FR_ITEM_POINTER(FR_TYPE_UINT32, &number), NULL, T_INVALID); - if (rcode == 0) { - if (number < 100) number = 100; - if (number > 10000) number = 10000; - - session->required_min_rx_interval = number * 1000; - } - } - - { - uint32_t number; - - rcode = cf_pair_parse(NULL, cs, "max_timeouts", FR_ITEM_POINTER(FR_TYPE_UINT32, &number), NULL, T_INVALID); - if (rcode == 0) { - if (number == 0) number = 1; - if (number > 10) number = 10; - - session->detect_multi = number; - } - } - session->auth_type = sock->auth_type; - - /* - * Parse / over-ride the secrets. - */ - session->secret_len = bfd_parse_secret(cs, session->secret); - if ((session->secret_len == 0) && - (session->auth_type != BFD_AUTH_RESERVED)) { - if (sock->secret_len == 0) { - cf_log_err(cf_section_to_item(cs), "auth_type requires a secret"); - talloc_free(session); - return NULL; - } - - session->secret_len = sock->secret_len; - memcpy(session->secret, sock->secret, sizeof(session->secret)); - } - - /* - * Initialize the detection time. - */ - if (!session->demand_mode) { - session->detection_time = session->required_min_rx_interval; - } else { - session->detection_time = session->desired_min_tx_interval; - } - session->detection_time *= session->detect_multi; - - /* - * And finally remember the session. - */ - session->socket.inet.dst_ipaddr = *ipaddr; - session->socket.inet.dst_port = port; - - session->socket.inet.src_ipaddr = sock->my_ipaddr; - session->socket.inet.src_port = sock->my_port; - - fr_ipaddr_to_sockaddr(&session->remote_sockaddr, &session->salen, - ipaddr, port); - - if (!fr_rb_insert(sock->session_tree, session)) { - ERROR("FAILED creating new session!"); - talloc_free(session); - return NULL; - } - - bfd_trigger(session); - - /* - * Check for threaded / non-threaded operation. - */ - if (event_list) { - session->el = event_list; - - bfd_start_control(session); - - session->pipefd[0] = session->pipefd[1] = -1; - session->pthread_id = pthread_self(); - } else { - if (!bfd_pthread_create(session)) { - fr_rb_delete(sock->session_tree, session); - talloc_free(session); - return NULL; - } - } - - return session; -} - - -static int bfd_verify_sequence(bfd_state_t *session, uint32_t sequence_no, - int keyed) -{ - uint32_t start, stop; - - start = session->recv_auth_seq; - if (keyed) { - start++; - } - stop = start + 3 * session->detect_multi; - - if (start < stop) { - if ((sequence_no < start) || - (sequence_no > stop)) { - return 0; - } - - } else { /* start is ~2^32, stop is ~10 */ - if ((sequence_no > start) && - (sequence_no < stop)) { - return 0; - } - } - - return 1; -} - -static void bfd_calc_md5(bfd_state_t *session, bfd_packet_t *bfd) -{ - bfd_auth_md5_t *md5 = &bfd->auth.md5; - - fr_assert(session->secret_len <= sizeof(md5->digest)); - fr_assert(md5->auth_len == sizeof(*md5)); - - memset(md5->digest, 0, sizeof(md5->digest)); - memcpy(md5->digest, session->secret, session->secret_len); - - fr_md5_calc(md5->digest,(const uint8_t *) bfd, bfd->length); -} - -static void bfd_auth_md5(bfd_state_t *session, bfd_packet_t *bfd) -{ - bfd_auth_md5_t *md5 = &bfd->auth.md5; - - md5->auth_type = session->auth_type; - md5->auth_len = sizeof(*md5); - bfd->length += md5->auth_len; - - md5->key_id = 0; - md5->sequence_no = session->xmit_auth_seq++; - - bfd_calc_md5(session, bfd); -} - -static int bfd_verify_md5(bfd_state_t *session, bfd_packet_t *bfd) -{ - int rcode; - bfd_auth_md5_t *md5 = &bfd->auth.md5; - uint8_t digest[sizeof(md5->digest)]; - - if (md5->auth_len != sizeof(*md5)) return 0; - - if (md5->key_id != 0) return 0; - - memcpy(digest, md5->digest, sizeof(digest)); - - bfd_calc_md5(session, bfd); - rcode = fr_digest_cmp(digest, md5->digest, sizeof(digest)); - - memcpy(md5->digest, digest, sizeof(md5->digest)); /* pedantic */ - - if (rcode != 0) { - DEBUG("BFD %d MD5 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****", session->number); - return 0; - } - - /* - * Do this AFTER the authentication instead of before! - */ - if (!session->auth_seq_known) { - session->auth_seq_known = 1; - - } else if (!bfd_verify_sequence(session, md5->sequence_no, - (md5->auth_type == BFD_AUTH_MET_KEYED_MD5))) { - DEBUG("MD5 sequence out of window"); - return 0; - } - - session->recv_auth_seq = md5->sequence_no; - - return 1; -} - -static void bfd_calc_sha1(bfd_state_t *session, bfd_packet_t *bfd) -{ - fr_sha1_ctx ctx; - bfd_auth_sha1_t *sha1 = &bfd->auth.sha1; - - fr_assert(session->secret_len <= sizeof(sha1->digest)); - fr_assert(sha1->auth_len == sizeof(*sha1)); - - memset(sha1->digest, 0, sizeof(sha1->digest)); - memcpy(sha1->digest, session->secret, session->secret_len); - - fr_sha1_init(&ctx); - fr_sha1_update(&ctx, (const uint8_t *) bfd, bfd->length); - fr_sha1_final(sha1->digest, &ctx); -} - -static void bfd_auth_sha1(bfd_state_t *session, bfd_packet_t *bfd) -{ - bfd_auth_sha1_t *sha1 = &bfd->auth.sha1; - - sha1->auth_type = session->auth_type; - sha1->auth_len = sizeof(*sha1); - bfd->length += sha1->auth_len; - - sha1->key_id = 0; - sha1->sequence_no = session->xmit_auth_seq++; - - bfd_calc_sha1(session, bfd); -} - -static int bfd_verify_sha1(bfd_state_t *session, bfd_packet_t *bfd) -{ - int rcode; - bfd_auth_sha1_t *sha1 = &bfd->auth.sha1; - uint8_t digest[sizeof(sha1->digest)]; - - if (sha1->auth_len != sizeof(*sha1)) return 0; - - if (sha1->key_id != 0) return 0; - - memcpy(digest, sha1->digest, sizeof(digest)); - - bfd_calc_sha1(session, bfd); - rcode = fr_digest_cmp(digest, sha1->digest, sizeof(digest)); - - memcpy(sha1->digest, digest, sizeof(sha1->digest)); /* pedantic */ - - if (rcode != 0) { - DEBUG("BFD %d SHA1 Digest failed: **** RE-ENTER THE SECRET ON BOTH ENDS ****", session->number); - return 0; - } - - /* - * Do this AFTER the authentication instead of before! - */ - if (!session->auth_seq_known) { - session->auth_seq_known = 1; - - } else if (!bfd_verify_sequence(session, sha1->sequence_no, - (sha1->auth_type == BFD_AUTH_MET_KEYED_SHA1))) { - DEBUG("SHA1 sequence out of window"); - return 0; - } - - session->recv_auth_seq = sha1->sequence_no; - - return 1; -} - - -static int bfd_authenticate(bfd_state_t *session, bfd_packet_t *bfd) -{ - switch (bfd->auth.basic.auth_type) { - case BFD_AUTH_RESERVED: - return 0; - - case BFD_AUTH_SIMPLE: - break; - - case BFD_AUTH_KEYED_MD5: - case BFD_AUTH_MET_KEYED_MD5: - return bfd_verify_md5(session, bfd); - - case BFD_AUTH_KEYED_SHA1: - case BFD_AUTH_MET_KEYED_SHA1: - return bfd_verify_sha1(session, bfd); - } - - return 0; -} - -static void bfd_control_packet_init(bfd_state_t *session, - bfd_packet_t *bfd) -{ - memset(bfd, 0, sizeof(*bfd)); - - bfd->version = 1; - bfd->diag = session->local_diag; - bfd->state = session->session_state; - bfd->poll = 0; /* fixed by poll response */ - bfd->final = 0; /* fixed by poll response */ - bfd->control_plane_independent = 0; - - if (session->auth_type == BFD_AUTH_RESERVED) { - bfd->auth_present = 0; - } else { - bfd->auth_present = 1; - } - - /* - * If we're UP / UP, signal that we've entered demand - * mode, and stop sending packets. - */ - if (session->demand_mode && - (session->session_state == BFD_STATE_UP) && - (session->remote_session_state == BFD_STATE_UP)) { - bfd->demand = true; - - DEBUG("BFD %d demand mode UP / UP, sending ACK and done.", - session->number); - bfd_stop_control(session); - } else { - bfd->demand = false; - } - - bfd->multipoint = 0; - bfd->detect_multi = session->detect_multi; - bfd->length = 24; /* auth types add to this later */ - - bfd->my_disc = session->local_disc; - bfd->your_disc = session->remote_disc; - - bfd->desired_min_tx_interval = session->desired_min_tx_interval; - bfd->required_min_rx_interval = session->required_min_rx_interval; - - bfd->min_echo_rx_interval = session->my_min_echo_rx_interval; -} - - -static void bfd_sign(bfd_state_t *session, bfd_packet_t *bfd) -{ - if (bfd->auth_present) { - switch (session->auth_type) { - case BFD_AUTH_RESERVED: - break; - - case BFD_AUTH_SIMPLE: - break; - - case BFD_AUTH_KEYED_MD5: - case BFD_AUTH_MET_KEYED_MD5: - bfd_auth_md5(session, bfd); - break; - - case BFD_AUTH_KEYED_SHA1: - case BFD_AUTH_MET_KEYED_SHA1: - bfd_auth_sha1(session, bfd); - break; - } - } -} - - -/* - * Send a packet. - */ -static void bfd_send_packet(UNUSED fr_event_list_t *eel, UNUSED fr_time_t now, void *ctx) -{ - bfd_state_t *session = ctx; - bfd_packet_t bfd; - - bfd_control_packet_init(session, &bfd); - - if (session->doing_poll) { - bfd.poll = 1; - } - - if (!bfd.demand) { - bfd_start_packets(session); - } - - bfd_sign(session, &bfd); - - DEBUG("BFD %d sending packet state %s", - session->number, bfd_state[session->session_state]); - if (sendto(session->socket.fd, &bfd, bfd.length, 0, - (struct sockaddr *) &session->remote_sockaddr, - session->salen) < 0) { - ERROR("Failed sending packet: %s", fr_syserror(errno)); - } -} - -static int bfd_start_packets(bfd_state_t *session) -{ - uint32_t interval, base; - uint64_t jitter; - - /* - * Reset the timers. - */ - fr_event_timer_delete(&session->ev_packet); - - session->last_sent = fr_time(); - - if (session->desired_min_tx_interval >= session->remote_min_rx_interval) { - interval = session->desired_min_tx_interval; - } else { - interval = session->remote_min_rx_interval; - } - base = (interval * 3) / 4; - jitter = fr_rand(); /* 32-bit number */ - - if (session->detect_multi == 1) { - jitter *= 644245094; /* 15% of 2^32 */ - - } else { - jitter *= (1 << 30); /* 25% of 2^32 */ - } - - jitter >>= 32; - jitter *= interval; - jitter >>= 32; - interval = base; - interval += jitter; - - if (fr_event_timer_in(session, session->el, &session->ev_packet, - fr_time_delta_from_usec(interval), - bfd_send_packet, session) < 0) { - fr_assert("Failed to insert event" == NULL); - } - - return 0; -} - - -static void bfd_set_timeout(bfd_state_t *session, fr_time_t when) -{ - fr_time_t now; - - fr_event_timer_delete(&session->ev_timeout); - - now = fr_time_add(when, fr_time_delta_from_usec(session->detection_time)); - - if (session->detect_multi >= 2) { - uint32_t delay; - - session->next_recv = when; - delay = session->detection_time / session->detect_multi; - delay += delay / 2; - - session->next_recv = fr_time_add(session->next_recv, fr_time_delta_from_usec(delay)); - } - - if (fr_event_timer_at(session, session->el, &session->ev_timeout, - now, bfd_detection_timeout, session) < 0) { - fr_assert("Failed to insert event" == NULL); - } -} - - -static int bfd_start_control(bfd_state_t *session) -{ - if (session->remote_min_rx_interval == 0) return 0; - - if ((session->remote_disc == 0) && session->passive) return 0; - - if (session->remote_demand_mode && - (session->session_state == BFD_STATE_UP) && - (session->remote_session_state == BFD_STATE_UP) && - !session->doing_poll) { - DEBUG("BFD %d warning: asked to start UP / UP ?", - session->number); - fr_assert(0 == 1); - bfd_stop_control(session); - return 0; - } - - bfd_set_timeout(session, session->last_recv); - - if (session->ev_packet) return 0; - - return bfd_start_packets(session); -} - -static int bfd_stop_control(bfd_state_t *session) -{ - fr_event_timer_delete(&session->ev_timeout); - fr_event_timer_delete(&session->ev_packet); - return 1; -} - - -static int bfd_start_poll(bfd_state_t *session) -{ - if (session->doing_poll) return 0; - - /* - * Already sending packets. Reset the timers and set the - * poll bit. - */ - if (!session->remote_demand_mode) { - bfd_stop_control(session); - } - - session->doing_poll = 1; - - /* - * Send POLL packets, even if we're not sending CONTROL - * packets. - */ - return bfd_start_packets(session); -} - -static int bfd_stop_poll(bfd_state_t *session) -{ - if (!session->doing_poll) return 0; - - /* - * We tried to increase the min_tx during a polling - * sequence. That isn't kosher, so we instead waited - * until now. - */ - if (session->next_min_tx_interval) { - session->desired_min_tx_interval = session->next_min_tx_interval; - session->next_min_tx_interval = 0; - } - - /* - * Already sending packets. Clear the poll bit and - * re-set the timers. - */ - if (!session->remote_demand_mode) { - fr_assert(session->ev_timeout != NULL); - fr_assert(session->ev_packet != NULL); - session->doing_poll = 0; - - bfd_stop_control(session); - bfd_start_control(session); - return 1; - } - - session->doing_poll = 0; - - return bfd_stop_control(session); -} - -static void bfd_set_desired_min_tx_interval(bfd_state_t *session, uint32_t value) -{ - /* - * Increasing the value: don't change it if we're already - * polling. - */ - if (session->doing_poll && - (session->session_state == BFD_STATE_UP) && - (value > session->desired_min_tx_interval)) { - session->next_min_tx_interval = value; - return; - } - - if (session->session_state != BFD_STATE_UP) { - if (value < USEC) value = USEC; - } - - session->desired_min_tx_interval = value; - bfd_stop_control(session); - session->doing_poll = 0; - - bfd_start_poll(session); -} - -static void bfd_detection_timeout(UNUSED fr_event_list_t *eel, fr_time_t now, void *ctx) -{ - bfd_state_t *session = ctx; - - DEBUG("BFD %d Timeout state %s ****** ", session->number, - bfd_state[session->session_state]); - - if (!session->demand_mode) { - switch (session->session_state) { - case BFD_STATE_INIT: - case BFD_STATE_UP: - goto start_poll; - - default: - break; - } - - } else if (!session->doing_poll) { - start_poll: - DEBUG("BFD %d State -> DOWN (control expired)", session->number); - session->session_state = BFD_STATE_DOWN; - session->local_diag = BFD_CTRL_EXPIRED; - bfd_trigger(session); - - bfd_set_desired_min_tx_interval(session, USEC); - } - - session->remote_disc = 0; - - if (session->detection_timeouts >= 2) { - session->auth_seq_known = 0; - } - - session->detection_timeouts++; - - bfd_set_timeout(session, now); -} - - -/* - * Send an immediate response to a poll request. - * - * Note that this doesn't affect our "last_sent" timer. - * That's set only when we intend to send a packet. - */ -static void bfd_poll_response(bfd_state_t *session) -{ - bfd_packet_t bfd; - - bfd_control_packet_init(session, &bfd); - bfd.poll = 0; /* Section 6.5 */ - bfd.final = 1; - - /* - * TO DO: rate limit poll responses. - */ - - bfd_sign(session, &bfd); - - if (sendto(session->socket.fd, &bfd, bfd.length, 0, - (struct sockaddr *) &session->remote_sockaddr, - session->salen) < 0) { - ERROR("Failed sending poll response: %s", fr_syserror(errno)); - } -} - - -static int bfd_process(bfd_state_t *session, bfd_packet_t *bfd) -{ - if (bfd->auth_present && - (session->auth_type == BFD_AUTH_RESERVED)) { - DEBUG("BFD %d packet asked to authenticate an unauthenticated session.", session->number); - return 0; - } - - if (!bfd->auth_present && - (session->auth_type != BFD_AUTH_RESERVED)) { - DEBUG("BFD %d packet failed to authenticate an authenticated session.", session->number); - return 0; - } - - if (bfd->auth_present && !bfd_authenticate(session, bfd)) { - return 0; - } - - DEBUG("BFD %d processing packet", session->number); - session->remote_disc = bfd->my_disc; - session->remote_session_state = bfd->state; - session->remote_demand_mode = bfd->demand; - - /* - * The other end is reducing the RX interval. Do that - * now. - */ - if ((bfd->required_min_rx_interval < session->remote_min_rx_interval) && - !session->demand_mode) { - bfd_stop_control(session); - bfd_start_control(session); - } - session->remote_min_rx_interval = bfd->required_min_rx_interval; - - session->remote_min_echo_rx_interval = bfd->min_echo_rx_interval; - if (bfd->min_echo_rx_interval == 0) { -#if 0 - /* - * Echo packets are BFD packets with - * application-layer data echoed back to the - * sender. We don't do that. - */ - bfd_stop_echo(session); -#endif - } - - if (session->doing_poll && bfd->final) { - bfd_stop_poll(session); - } - - /* - * Update transmit intervals as in 6.8.7 - */ - - /* - * Update detection times as in 6.8.4 - */ - if (!session->demand_mode) { - if (session->required_min_rx_interval >= bfd->desired_min_tx_interval) { - session->detection_time = session->required_min_rx_interval; - } else { - session->detection_time = bfd->desired_min_tx_interval; - } - } else { - if (session->desired_min_tx_interval >= session->remote_min_rx_interval) { - session->detection_time = session->desired_min_tx_interval; - } else { - session->detection_time = session->remote_min_rx_interval; - } - } - session->detection_time *= session->detect_multi; - - if (session->session_state == BFD_STATE_ADMIN_DOWN) { - DEBUG("Discarding BFD packet (admin down)"); - return 0; - } - - if (bfd->state == BFD_STATE_ADMIN_DOWN) { - if (bfd->state != BFD_STATE_DOWN) { - session->local_diag = BFD_NEIGHBOR_DOWN; - } - - DEBUG("BFD %d State %s -> DOWN (admin down)", - session->number, bfd_state[session->session_state]); - session->session_state = BFD_STATE_DOWN; - bfd_trigger(session); - - bfd_set_desired_min_tx_interval(session, USEC); - - } else { - switch (session->session_state) { - case BFD_STATE_DOWN: - switch (bfd->state) { - case BFD_STATE_DOWN: - DEBUG("BFD %d State DOWN -> INIT (neighbor down)", - session->number); - session->session_state = BFD_STATE_INIT; - bfd_trigger(session); - - bfd_set_desired_min_tx_interval(session, USEC); - break; - - case BFD_STATE_INIT: - DEBUG("BFD %d State DOWN -> UP (neighbor INIT)", - session->number); - session->session_state = BFD_STATE_UP; - bfd_trigger(session); - break; - - default: /* don't change anything */ - break; - } - break; - - case BFD_STATE_INIT: - switch (bfd->state) { - case BFD_STATE_INIT: - case BFD_STATE_UP: - DEBUG("BFD %d State INIT -> UP", - session->number); - session->session_state = BFD_STATE_UP; - bfd_trigger(session); - break; - - default: /* don't change anything */ - break; - } - break; - - case BFD_STATE_UP: - switch (bfd->state) { - case BFD_STATE_DOWN: - session->local_diag = BFD_NEIGHBOR_DOWN; - - DEBUG("BFD %d State UP -> DOWN (neighbor down)", session->number); - session->session_state = BFD_STATE_DOWN; - bfd_trigger(session); - - bfd_set_desired_min_tx_interval(session, USEC); - break; - - default: - break; - } - break; - - default: - DEBUG("Internal sanity check failed"); - return 0; - } - } - - /* - * Check if demand mode should be active (Section 6.6) - */ - if (session->remote_demand_mode && - (session->session_state == BFD_STATE_UP) && - (session->remote_session_state == BFD_STATE_UP)) { - DEBUG("BFD %d demand mode UP / UP, stopping packets", session->number); - bfd_stop_control(session); - } - - if (bfd->poll) { - bfd_poll_response(session); - } - - /* - * We've received the packet for the purpose of Section - * 6.8.4. - */ - session->last_recv = fr_time(); - - /* - * We've received a packet, but missed the previous one. - * Warn about it. - */ - if ((session->detect_multi >= 2) && (fr_time_gt(session->last_recv, session->next_recv))) { - fr_radius_packet_t packet; - request_t request; - - bfd_request(session, &request, &packet); - - trigger_exec(unlang_interpret_get_thread_default(), NULL, "server.bfd.warn", false, NULL); - } - - - if ((!session->remote_demand_mode) || - (session->session_state != BFD_STATE_UP) || - (session->remote_session_state != BFD_STATE_UP)) { - bfd_start_control(session); - } - - if (session->server_cs) { - request_t *request; - fr_radius_packet_t *packet, *reply; - - request = request_alloc_internal(session, NULL); - packet = fr_radius_packet_alloc(request, 0); - reply = fr_radius_packet_alloc(request, 0); - - bfd_request(session, request, packet); - - memset(reply, 0, sizeof(*reply)); - - request->reply = reply; - fr_socket_addr_swap(&request->reply->socket, &session->socket); - - /* - * FIXME: add my state, remote state as VPs? - */ - if (fr_debug_lvl) { - request->log.dst = talloc_zero(request, log_dst_t); - request->log.dst->func = vlog_request; - request->log.dst->uctx = &default_log; - - request->log.lvl = fr_debug_lvl; - } - request->component = NULL; - request->module = NULL; - - DEBUG2("server %s {", cf_section_name2(unlang_call_current(request))); - if (unlang_interpret_push_section(request, session->unlang, RLM_MODULE_NOTFOUND, UNLANG_TOP_FRAME) < 0) { - talloc_free(request); - return 0; - } - unlang_interpret_synchronous(unlang_interpret_event_list(request), request); - DEBUG("}"); - - /* - * FIXME: grab attributes from the reply - * and cache them for use in the next request. - */ - talloc_free(request); - } - - return 1; -} - - -/* - * Requirements of 6.8.3 - * - * Changes to: - * - * session->desired_min_tx_interval - * session->required_min_rx_interval - * - * mean we start polling. - */ - -/* - * Check if an incoming request is "ok" - * - * It takes packets, not requests. It sees if the packet looks - * OK. If so, it does a number of sanity checks on it. - */ -static int bfd_socket_recv(rad_listen_t *listener) -{ - ssize_t rcode; - bfd_socket_t *sock = listener->data; - bfd_state_t *session; - bfd_state_t my_session; - struct sockaddr_storage src; - socklen_t sizeof_src = sizeof(src); - bfd_packet_t bfd; - - rcode = recvfrom(listener->fd, &bfd, sizeof(bfd), 0, - (struct sockaddr *)&src, &sizeof_src); - if (rcode < 0) { - ERROR("Failed receiving packet: %s", fr_syserror(errno)); - return 0; - } - - if (rcode < 24) { - DEBUG("BFD packet is too short (%d < 24)", (int) rcode); - return 0; - } - - if (bfd.version != 1) { - DEBUG("BFD packet has wrong version (%d != 1)", bfd.version); - return 0; - } - - if (bfd.length < 24) { - DEBUG("BFD packet has wrong length (%d < 24)", bfd.length); - return 0; - } - - if (bfd.length > sizeof(bfd)) { - DEBUG("BFD packet has wrong length (%d > %zd)", bfd.length, sizeof(bfd)); - return 0; - } - - if (bfd.auth_present) { - if (bfd.length < 26) { - DEBUG("BFD packet has wrong length (%d < 26)", - bfd.length); - return 0; - } - - if (bfd.length < 24 + bfd.auth.basic.auth_len) { - DEBUG("BFD packet is too short (%d < %d)", - bfd.length, 24 + bfd.auth.basic.auth_len); - return 0; - - } - - if (bfd.length != 24 + bfd.auth.basic.auth_len) { - DEBUG("WARNING: What is the extra data?"); - } - - } - - if (bfd.detect_multi == 0) { - DEBUG("BFD packet has detect_multi == 0"); - return 0; - } - - if (bfd.multipoint != 0) { - DEBUG("BFD packet has multi != 0"); - return 0; - } - - if (bfd.my_disc == 0) { - DEBUG("BFD packet has my_disc == 0"); - return 0; - } - - if ((bfd.your_disc == 0) && - !((bfd.state == BFD_STATE_DOWN) || - (bfd.state == BFD_STATE_ADMIN_DOWN))) { - DEBUG("BFD packet has invalid your-disc / state"); - return 0; - } - - /* - * We SHOULD use "your_disc", but what the heck. - */ - fr_ipaddr_from_sockaddr(&my_session.socket.inet.dst_ipaddr, - &my_session.socket.inet.dst_port, &src, sizeof_src); - - session = fr_rb_find(sock->session_tree, &my_session); - if (!session) { - DEBUG("BFD unknown peer"); - return 0; - } - - if (!event_list) { - uint8_t *p = (uint8_t *) &bfd; - size_t total = bfd.length; - - /* - * A child has had a problem. Do some cleanups. - */ - if (session->blocked) bfd_pthread_free(session); - - /* - * No event list, try to create a new one. - */ - if (!session->el && !bfd_pthread_create(session)) { - DEBUG("BFD %d - error trying to create child thread", - session->number); - return 0; - } - - do { - rcode = write(session->pipefd[1], p, total); - if ((rcode < 0) && (errno == EINTR)) continue; - - if (rcode < 0) { - session->blocked = true; - return 0; - } - - total -= rcode; - p += rcode; - } while (total > 0); - return 0; - } - - return bfd_process(session, &bfd); -} - -static int bfd_parse_ip_port(CONF_SECTION *cs, fr_ipaddr_t *ipaddr, uint16_t *port) -{ - int rcode; - - /* - * Try IPv4 first - */ - memset(ipaddr, 0, sizeof(*ipaddr)); - ipaddr->addr.v4.s_addr = htonl(INADDR_NONE); - rcode = cf_pair_parse(NULL, cs, "ipaddr", FR_ITEM_POINTER(FR_TYPE_IPV4_ADDR, ipaddr), NULL, T_INVALID); - if (rcode < 0) return -1; - - if (rcode == 0) { /* successfully parsed IPv4 */ - ipaddr->af = AF_INET; - - } else { /* maybe IPv6? */ - rcode = cf_pair_parse(NULL, cs, "ipv6addr", FR_ITEM_POINTER(FR_TYPE_IPV6_ADDR, ipaddr), NULL, T_INVALID); - if (rcode < 0) return -1; - - if (rcode == 1) { - cf_log_err(cf_section_to_item(cs), - "No address specified in section"); - return -1; - } - ipaddr->af = AF_INET6; - } - - rcode = cf_pair_parse(NULL, cs, "port", FR_ITEM_POINTER(FR_TYPE_UINT16, port), "0", T_INVALID); - if (rcode < 0) return -1; - - return 0; -} - -/* - * @fixme: move some of this to parse - */ -static int bfd_init_sessions(CONF_SECTION *cs, bfd_socket_t *sock, int sockfd) -{ - CONF_ITEM *ci; - CONF_SECTION *peer; - uint16_t port; - fr_ipaddr_t ipaddr; - - for (ci=cf_item_next(cs, NULL); - ci != NULL; - ci=cf_item_next(cs, ci)) { - bfd_state_t *session, my_session; - - if (!cf_item_is_section(ci)) continue; - - peer = cf_item_to_section(ci); - - if (strcmp(cf_section_name1(peer), "peer") != 0) continue; - - if (bfd_parse_ip_port(peer, &ipaddr, &port) < 0) { - return -1; - } - - my_session.socket.inet.dst_ipaddr = ipaddr; - my_session.socket.inet.dst_port = port; - if (fr_rb_find(sock->session_tree, &my_session) != NULL) { - cf_log_err(ci, "Peers must have unique IP addresses"); - return -1; - } - - session = bfd_new_session(sock, sockfd, peer, &ipaddr, port); - if (!session) return -1; - } - - return 0; -} - - -/* - * None of these functions are used. - */ -static int bfd_socket_send(UNUSED rad_listen_t *listener, UNUSED request_t *request) -{ - fr_assert(0 == 1); - return 0; -} - - -static int bfd_socket_encode(UNUSED rad_listen_t *listener, UNUSED request_t *request) -{ - fr_assert(0 == 1); - return 0; -} - - -static int bfd_socket_decode(UNUSED rad_listen_t *listener, UNUSED request_t *request) -{ - fr_assert(0 == 1); - return 0; -} - -static int8_t bfd_session_cmp(const void *one, const void *two) -{ - const bfd_state_t *a = one, *b = two; - - return fr_ipaddr_cmp(&a->socket.inet.dst_ipaddr, &b->socket.inet.dst_ipaddr); -} - -static fr_table_num_sorted_t const auth_types[] = { - { L("keyed-md5"), BFD_AUTH_KEYED_MD5 }, - { L("keyed-sha1"), BFD_AUTH_KEYED_SHA1 }, - { L("met-keyed-md5"), BFD_AUTH_MET_KEYED_MD5 }, - { L("met-keyed-sha1"), BFD_AUTH_MET_KEYED_SHA1 }, - { L("none"), BFD_AUTH_RESERVED }, - { L("simple"), BFD_AUTH_SIMPLE } -}; -static size_t auth_types_len = NUM_ELEMENTS(auth_types); - -static int bfd_socket_parse(CONF_SECTION *cs, rad_listen_t *this) -{ - bfd_socket_t *sock = this->data; - char const *auth_type_str = NULL; - uint16_t listen_port; - fr_ipaddr_t ipaddr; - - fr_assert(sock != NULL); - - if (bfd_parse_ip_port(cs, &ipaddr, &listen_port) < 0) { - return -1; - } - - sock->my_ipaddr = ipaddr; - sock->my_port = listen_port; - - if (cf_pair_parse(sock, cs, "interface", FR_ITEM_POINTER(FR_TYPE_STRING, &sock->interface), NULL, T_INVALID) < 0) return -1; - - if (cf_pair_parse(sock, cs, "min_receive_interval", FR_ITEM_POINTER(FR_TYPE_UINT32, - &sock->min_rx_interval), "1000", T_BARE_WORD) < 0) return -1; - if (cf_pair_parse(sock, cs, "max_timeouts", FR_ITEM_POINTER(FR_TYPE_UINT32, - &sock->max_timeouts), "3", T_BARE_WORD) < 0) return -1; - if (cf_pair_parse(sock, cs, "demand", FR_ITEM_POINTER(FR_TYPE_BOOL, &sock->demand), - "no", T_DOUBLE_QUOTED_STRING) < 0) return -1; - if (cf_pair_parse(NULL, cs, "auth_type", FR_ITEM_POINTER(FR_TYPE_STRING, &auth_type_str), - NULL, T_INVALID) < 0) return -1; - - if (!this->server) { - char const *server; - if (cf_pair_parse(sock, cs, "server", FR_ITEM_POINTER(FR_TYPE_STRING, &server), - NULL, T_INVALID) < 0) return -1; - sock->server_cs = virtual_server_find(server); - } else { - sock->server_cs = this->server_cs; - } - - if (sock->min_tx_interval < 100) sock->min_tx_interval = 100; - if (sock->min_tx_interval > 10000) sock->min_tx_interval = 10000; - - if (sock->min_rx_interval < 100) sock->min_rx_interval = 100; - if (sock->min_rx_interval > 10000) sock->min_rx_interval = 10000; - - if (sock->max_timeouts == 0) sock->max_timeouts = 1; - if (sock->max_timeouts > 10) sock->max_timeouts = 10; - - sock->auth_type = fr_table_value_by_str(auth_types, auth_type_str, BFD_AUTH_INVALID); - if (sock->auth_type == BFD_AUTH_INVALID) { - ERROR("Unknown auth_type '%s'", auth_type_str); - return -1; - } - - if (sock->auth_type == BFD_AUTH_SIMPLE) { - ERROR("'simple' authentication is insecure and is not supported"); - return -1; - } - - if (sock->auth_type != BFD_AUTH_RESERVED) { - sock->secret_len = bfd_parse_secret(cs, sock->secret); - - if (sock->secret_len == 0) { - ERROR("Cannot have empty secret"); - return -1; - } - - if (((sock->auth_type == BFD_AUTH_KEYED_MD5) || - (sock->auth_type == BFD_AUTH_MET_KEYED_MD5)) && - (sock->secret_len > 16)) { - ERROR("Secret must be no more than 16 bytes when using MD5"); - return -1; - } - } - - sock->session_tree = fr_rb_inline_talloc_alloc(sock, bfd_state_t, node, bfd_session_cmp, bfd_session_free); - if (!sock->session_tree) { - ERROR("Failed creating session tree!"); - return -1; - } - - /* - * Find the sibling "bfd" section of the "listen" section. - */ - sock->unlang = cf_section_find(cf_item_to_section(cf_parent(cs)), "bfd", NULL); - - return 0; -} - -static int bfd_socket_open(CONF_SECTION *cs, rad_listen_t *this) -{ - int rcode; - int ttl = 255; - uint16_t port; - bfd_socket_t *sock = this->data; - - port = sock->my_port; - - this->fd = fr_socket_server_udp(&sock->my_ipaddr, &port, "bfd-control", true); - if (this->fd < 0) { - char buffer[256]; - - this->print(this, buffer, sizeof(buffer)); - - ERROR("Failed opening %s: %s", buffer, fr_syserror(errno)); - return -1; - } - - if (setsockopt(this->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) goto fail; - - rad_suid_up(); - rcode = fr_socket_bind(this->fd, &sock->my_ipaddr, &port, sock->interface); - rad_suid_down(); - sock->my_port = port; - - if (rcode < 0) { - char buffer[256]; - - fail: - close(this->fd); - - this->print(this, buffer, sizeof(buffer)); - ERROR("Failed binding to %s: %s", buffer, fr_syserror(errno)); - return -1; - } - - /* - * Bootstrap the initial set of connections. - */ - if (bfd_init_sessions(cs, sock, this->fd) < 0) { - return -1; - } - - return 0; -} - -static int bfd_socket_print(const rad_listen_t *this, char *buffer, size_t bufsize) -{ - size_t len; - bfd_socket_t *sock = this->data; - -#define FORWARD len = strlen(buffer); if (len >= (bufsize + 1)) return 0;buffer += len;bufsize -= len - - strlcpy(buffer, "bfd address ", bufsize); - FORWARD; - - if ((sock->my_ipaddr.af == AF_INET) && - (sock->my_ipaddr.addr.v4.s_addr == htonl(INADDR_ANY))) { - strlcpy(buffer, "*", bufsize); - } else { - fr_inet_ntoh(&sock->my_ipaddr, buffer, bufsize); - } - FORWARD; - - strlcpy(buffer, " port ", bufsize); - FORWARD; - - snprintf(buffer, bufsize, "%d", sock->my_port); - FORWARD; - - return 1; -} - -/* - * If there's no "bfd" section, we can't bootstrap anything. - */ -static int bfd_socket_bootstrap(CONF_SECTION *server_cs, UNUSED CONF_SECTION *listen_cs) -{ - CONF_SECTION *cs; - - cs = cf_section_find(server_cs, "bfd", NULL); - if (!cs) { - cf_log_err(server_cs, "No 'bfd' sub-section found"); - return -1; - } - - return 0; -} - -/* - * Ensure that the "bfd" section is compiled. - */ -static int bfd_socket_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *listen_cs) -{ - CONF_SECTION *cs; - - cs = cf_section_find(server_cs, "bfd", NULL); - if (!cs) { - cf_log_err(server_cs, "No 'bfd' sub-section found"); - return -1; - } - - cf_log_debug(cs, "Loading bfd {...}"); - - if (unlang_compile(cs, MOD_AUTHORIZE, NULL, NULL) < 0) { - cf_log_err(cs, "Failed compiling 'bfd' section"); - return -1; - } - - return 0; -} - - -extern rad_protocol_t proto_bfd; -rad_protocol_t proto_bfd = { - .magic = MODULE_MAGIC_INIT, - .name = "bfd", - .inst_size = sizeof(bfd_socket_t), - .transports = TRANSPORT_UDP, - .tls = false, - .bootstrap = bfd_socket_bootstrap, - .compile = bfd_socket_compile, - .parse = bfd_socket_parse, - .open = bfd_socket_open, - .recv = bfd_socket_recv, - .send = bfd_socket_send, - .print = bfd_socket_print, - .debug = common_packet_debug, - .encode = bfd_socket_encode, - .decode = bfd_socket_decode -};