mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
pimd: add support for MSDP authentication
Implement MSDP MD5 authentication connection support. Implementation details: - Move the MSDP socket creation code to a generic function so it can be parametrized to be used with/without authentication. - The MSDP peer connection will not change when the configuration is set, instead it will only be applied next connection or when `clear ip msdp peer A.B.C.D` is called. Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
parent
13126dec14
commit
bd838d8c89
|
@ -2823,6 +2823,39 @@ DEFPY (clear_ip_mroute_count,
|
||||||
return clear_ip_mroute_count_command(vty, name);
|
return clear_ip_mroute_count_command(vty, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd,
|
||||||
|
"clear ip msdp peer A.B.C.D$peer [vrf WORD$vrfname]",
|
||||||
|
CLEAR_STR
|
||||||
|
IP_STR
|
||||||
|
MSDP_STR
|
||||||
|
"Restart MSDP peer\n"
|
||||||
|
"MSDP peer address\n"
|
||||||
|
VRF_CMD_HELP_STR)
|
||||||
|
{
|
||||||
|
const struct pim_instance *pim;
|
||||||
|
const struct listnode *node;
|
||||||
|
const struct vrf *vrf;
|
||||||
|
struct pim_msdp_peer *mp;
|
||||||
|
|
||||||
|
if (vrfname) {
|
||||||
|
vrf = vrf_lookup_by_name(vrfname);
|
||||||
|
if (vrf == NULL)
|
||||||
|
return CMD_WARNING;
|
||||||
|
} else
|
||||||
|
vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
||||||
|
|
||||||
|
pim = vrf->info;
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) {
|
||||||
|
if (mp->peer.s_addr != peer.s_addr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pim_msdp_peer_restart(mp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (show_ip_mroute_count,
|
DEFPY (show_ip_mroute_count,
|
||||||
show_ip_mroute_count_cmd,
|
show_ip_mroute_count_cmd,
|
||||||
"show ip mroute [vrf NAME] count [json$json]",
|
"show ip mroute [vrf NAME] count [json$json]",
|
||||||
|
@ -6285,6 +6318,57 @@ DEFPY_ATTR(ip_pim_msdp_peer,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY(msdp_peer_md5, msdp_peer_md5_cmd,
|
||||||
|
"msdp peer A.B.C.D$peer password WORD$psk",
|
||||||
|
CFG_MSDP_STR
|
||||||
|
"Configure MSDP peer\n"
|
||||||
|
"MSDP Peer address\n"
|
||||||
|
"Use MD5 authentication\n"
|
||||||
|
"MD5 pre shared key\n")
|
||||||
|
{
|
||||||
|
const struct lyd_node *peer_node;
|
||||||
|
char xpath[XPATH_MAXLEN + 24];
|
||||||
|
|
||||||
|
snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']",
|
||||||
|
VTY_CURR_XPATH, peer_str);
|
||||||
|
peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath);
|
||||||
|
if (peer_node == NULL) {
|
||||||
|
vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, "MD5");
|
||||||
|
nb_cli_enqueue_change(vty, "./authentication-key", NB_OP_MODIFY, psk);
|
||||||
|
|
||||||
|
return nb_cli_apply_changes(vty, "%s", xpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(no_msdp_peer_md5, no_msdp_peer_md5_cmd,
|
||||||
|
"no msdp peer A.B.C.D$peer password [WORD]",
|
||||||
|
NO_STR
|
||||||
|
CFG_MSDP_STR
|
||||||
|
"Configure MSDP peer\n"
|
||||||
|
"MSDP Peer address\n"
|
||||||
|
"Use MD5 authentication\n"
|
||||||
|
"MD5 pre shared key\n")
|
||||||
|
{
|
||||||
|
const struct lyd_node *peer_node;
|
||||||
|
char xpath[XPATH_MAXLEN + 24];
|
||||||
|
|
||||||
|
snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']",
|
||||||
|
VTY_CURR_XPATH, peer_str);
|
||||||
|
peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath);
|
||||||
|
if (peer_node == NULL) {
|
||||||
|
vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY,
|
||||||
|
"None");
|
||||||
|
|
||||||
|
return nb_cli_apply_changes(vty, "%s", xpath);
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY(pim_msdp_timers, pim_msdp_timers_cmd,
|
DEFPY(pim_msdp_timers, pim_msdp_timers_cmd,
|
||||||
"msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]",
|
"msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]",
|
||||||
CFG_MSDP_STR
|
CFG_MSDP_STR
|
||||||
|
@ -8320,6 +8404,8 @@ void pim_cmd_init(void)
|
||||||
|
|
||||||
install_element(PIM_NODE, &pim_msdp_peer_cmd);
|
install_element(PIM_NODE, &pim_msdp_peer_cmd);
|
||||||
install_element(PIM_NODE, &no_pim_msdp_peer_cmd);
|
install_element(PIM_NODE, &no_pim_msdp_peer_cmd);
|
||||||
|
install_element(PIM_NODE, &msdp_peer_md5_cmd);
|
||||||
|
install_element(PIM_NODE, &no_msdp_peer_md5_cmd);
|
||||||
install_element(PIM_NODE, &pim_msdp_timers_cmd);
|
install_element(PIM_NODE, &pim_msdp_timers_cmd);
|
||||||
install_element(PIM_NODE, &no_pim_msdp_timers_cmd);
|
install_element(PIM_NODE, &no_pim_msdp_timers_cmd);
|
||||||
install_element(PIM_NODE, &msdp_peer_sa_filter_cmd);
|
install_element(PIM_NODE, &msdp_peer_sa_filter_cmd);
|
||||||
|
@ -8462,6 +8548,7 @@ void pim_cmd_init(void)
|
||||||
install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd);
|
install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd);
|
||||||
|
|
||||||
install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd);
|
install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd);
|
||||||
|
install_element(ENABLE_NODE, &clear_ip_msdp_peer_cmd);
|
||||||
install_element(ENABLE_NODE, &clear_ip_interfaces_cmd);
|
install_element(ENABLE_NODE, &clear_ip_interfaces_cmd);
|
||||||
install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
|
install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
|
||||||
install_element(ENABLE_NODE, &clear_ip_mroute_cmd);
|
install_element(ENABLE_NODE, &clear_ip_mroute_cmd);
|
||||||
|
|
|
@ -26,6 +26,7 @@ DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info");
|
||||||
DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
|
DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
|
||||||
DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
|
DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
|
||||||
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name");
|
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name");
|
||||||
|
DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key");
|
||||||
DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache");
|
DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache");
|
||||||
DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group");
|
DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group");
|
||||||
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr");
|
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr");
|
||||||
|
|
|
@ -28,6 +28,7 @@ DECLARE_MTYPE(PIM_MSDP_MG_NAME);
|
||||||
DECLARE_MTYPE(PIM_MSDP_SA);
|
DECLARE_MTYPE(PIM_MSDP_SA);
|
||||||
DECLARE_MTYPE(PIM_MSDP_MG);
|
DECLARE_MTYPE(PIM_MSDP_MG);
|
||||||
DECLARE_MTYPE(PIM_MSDP_MG_MBR);
|
DECLARE_MTYPE(PIM_MSDP_MG_MBR);
|
||||||
|
DECLARE_MTYPE(PIM_MSDP_AUTH_KEY);
|
||||||
DECLARE_MTYPE(PIM_SEC_ADDR);
|
DECLARE_MTYPE(PIM_SEC_ADDR);
|
||||||
DECLARE_MTYPE(PIM_JP_AGG_GROUP);
|
DECLARE_MTYPE(PIM_JP_AGG_GROUP);
|
||||||
DECLARE_MTYPE(PIM_JP_AGG_SOURCE);
|
DECLARE_MTYPE(PIM_JP_AGG_SOURCE);
|
||||||
|
|
|
@ -773,7 +773,10 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp)
|
||||||
* first listening peer is configured; but don't bother tearing it down
|
* first listening peer is configured; but don't bother tearing it down
|
||||||
* when
|
* when
|
||||||
* all the peers go down */
|
* all the peers go down */
|
||||||
pim_msdp_sock_listen(mp->pim);
|
if (mp->auth_type == MSDP_AUTH_NONE)
|
||||||
|
pim_msdp_sock_listen(mp->pim);
|
||||||
|
else
|
||||||
|
pim_msdp_sock_auth_listen(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 11.2.A4 and 11.2.A5: transition active or passive peer to
|
/* 11.2.A4 and 11.2.A5: transition active or passive peer to
|
||||||
|
@ -1045,6 +1048,7 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim,
|
||||||
|
|
||||||
mp->state = PIM_MSDP_INACTIVE;
|
mp->state = PIM_MSDP_INACTIVE;
|
||||||
mp->fd = -1;
|
mp->fd = -1;
|
||||||
|
mp->auth_listen_sock = -1;
|
||||||
strlcpy(mp->last_reset, "-", sizeof(mp->last_reset));
|
strlcpy(mp->last_reset, "-", sizeof(mp->last_reset));
|
||||||
/* higher IP address is listener */
|
/* higher IP address is listener */
|
||||||
if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) {
|
if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) {
|
||||||
|
@ -1100,6 +1104,12 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp)
|
||||||
stream_fifo_free(mp->obuf);
|
stream_fifo_free(mp->obuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free authentication data. */
|
||||||
|
event_cancel(&mp->auth_listen_ev);
|
||||||
|
XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key);
|
||||||
|
if (mp->auth_listen_sock != -1)
|
||||||
|
close(mp->auth_listen_sock);
|
||||||
|
|
||||||
XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
|
XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
|
||||||
|
|
||||||
mp->pim = NULL;
|
mp->pim = NULL;
|
||||||
|
@ -1128,19 +1138,32 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp)
|
||||||
*mp = NULL;
|
*mp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
|
void pim_msdp_peer_restart(struct pim_msdp_peer *mp)
|
||||||
const struct in_addr *addr)
|
|
||||||
{
|
{
|
||||||
|
/* Stop auth listening socket if any. */
|
||||||
|
event_cancel(&mp->auth_listen_ev);
|
||||||
|
if (mp->auth_listen_sock != -1) {
|
||||||
|
close(mp->auth_listen_sock);
|
||||||
|
mp->auth_listen_sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop previously running connection. */
|
||||||
pim_msdp_peer_stop_tcp_conn(mp, true);
|
pim_msdp_peer_stop_tcp_conn(mp, true);
|
||||||
|
|
||||||
mp->local = *addr;
|
/* Start connection again. */
|
||||||
|
|
||||||
if (PIM_MSDP_PEER_IS_LISTENER(mp))
|
if (PIM_MSDP_PEER_IS_LISTENER(mp))
|
||||||
pim_msdp_peer_listen(mp);
|
pim_msdp_peer_listen(mp);
|
||||||
else
|
else
|
||||||
pim_msdp_peer_connect(mp);
|
pim_msdp_peer_connect(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
|
||||||
|
const struct in_addr *addr)
|
||||||
|
{
|
||||||
|
mp->local = *addr;
|
||||||
|
pim_msdp_peer_restart(mp);
|
||||||
|
}
|
||||||
|
|
||||||
/* peer hash and peer list helpers */
|
/* peer hash and peer list helpers */
|
||||||
static unsigned int pim_msdp_peer_hash_key_make(const void *p)
|
static unsigned int pim_msdp_peer_hash_key_make(const void *p)
|
||||||
{
|
{
|
||||||
|
@ -1318,6 +1341,10 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim)
|
||||||
vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer,
|
vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer,
|
||||||
&mp->local);
|
&mp->local);
|
||||||
|
|
||||||
|
if (mp->auth_type == MSDP_AUTH_MD5)
|
||||||
|
vty_out(vty, " msdp peer %pI4 password %s\n", &mp->peer,
|
||||||
|
mp->auth_key);
|
||||||
|
|
||||||
if (mp->acl_in)
|
if (mp->acl_in)
|
||||||
vty_out(vty, " msdp peer %pI4 sa-filter %s in\n",
|
vty_out(vty, " msdp peer %pI4 sa-filter %s in\n",
|
||||||
&mp->peer, mp->acl_in);
|
&mp->peer, mp->acl_in);
|
||||||
|
|
|
@ -89,6 +89,11 @@ enum pim_msdp_peer_flags {
|
||||||
PIM_MSDP_PEERF_IN_GROUP = (1 << 2),
|
PIM_MSDP_PEERF_IN_GROUP = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum msdp_auth_type {
|
||||||
|
MSDP_AUTH_NONE = 0,
|
||||||
|
MSDP_AUTH_MD5 = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct pim_msdp_peer {
|
struct pim_msdp_peer {
|
||||||
struct pim_instance *pim;
|
struct pim_instance *pim;
|
||||||
|
|
||||||
|
@ -98,6 +103,13 @@ struct pim_msdp_peer {
|
||||||
char *mesh_group_name;
|
char *mesh_group_name;
|
||||||
char key_str[INET_ADDRSTRLEN];
|
char key_str[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
/* Authentication data. */
|
||||||
|
enum msdp_auth_type auth_type;
|
||||||
|
char *auth_key;
|
||||||
|
|
||||||
|
int auth_listen_sock;
|
||||||
|
struct event *auth_listen_ev;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
enum pim_msdp_peer_state state;
|
enum pim_msdp_peer_state state;
|
||||||
enum pim_msdp_peer_flags flags;
|
enum pim_msdp_peer_flags flags;
|
||||||
|
@ -309,6 +321,15 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp);
|
||||||
void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
|
void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
|
||||||
const struct in_addr *addr);
|
const struct in_addr *addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart peer's connection.
|
||||||
|
*
|
||||||
|
* This is used internally in MSDP and should be used by northbound
|
||||||
|
* when wanting to immediately apply connections settings such as
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
|
void pim_msdp_peer_restart(struct pim_msdp_peer *mp);
|
||||||
|
|
||||||
#else /* PIM_IPV == 6 */
|
#else /* PIM_IPV == 6 */
|
||||||
static inline void pim_msdp_init(struct pim_instance *pim,
|
static inline void pim_msdp_init(struct pim_instance *pim,
|
||||||
struct event_loop *master)
|
struct event_loop *master)
|
||||||
|
|
|
@ -49,6 +49,192 @@ static void pim_msdp_update_sock_send_buffer_size(int fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to reduce code duplication.
|
||||||
|
*
|
||||||
|
* \param vrf VRF pointer (`NULL` means default VRF)
|
||||||
|
* \param mp the MSDP session pointer.
|
||||||
|
* \returns valid file descriptor otherwise `-1`.
|
||||||
|
*/
|
||||||
|
static int _pim_msdp_sock_listen(const struct vrf *vrf,
|
||||||
|
const struct pim_msdp_peer *mp)
|
||||||
|
{
|
||||||
|
const struct interface *ifp;
|
||||||
|
int sock;
|
||||||
|
int rv;
|
||||||
|
socklen_t socklen;
|
||||||
|
struct sockaddr_in sin = {};
|
||||||
|
union sockunion su_peer = {};
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock == -1) {
|
||||||
|
zlog_warn("%s: socket: %s", __func__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
socklen = sizeof(sin);
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(PIM_MSDP_TCP_PORT);
|
||||||
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
||||||
|
sin.sin_len = socklen;
|
||||||
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
|
if (mp)
|
||||||
|
sin.sin_addr = mp->local;
|
||||||
|
|
||||||
|
sockopt_reuseaddr(sock);
|
||||||
|
sockopt_reuseport(sock);
|
||||||
|
|
||||||
|
/* Bind socket to VRF/address. */
|
||||||
|
if (vrf && vrf->vrf_id != VRF_DEFAULT) {
|
||||||
|
ifp = if_lookup_by_name(vrf->name, vrf->vrf_id);
|
||||||
|
if (ifp == NULL) {
|
||||||
|
flog_err(EC_LIB_INTERFACE,
|
||||||
|
"%s: Unable to lookup vrf interface: %s",
|
||||||
|
__func__, vrf->name);
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vrf_bind(vrf->vrf_id, sock, ifp->name) == -1) {
|
||||||
|
flog_err_sys(EC_LIB_SOCKET,
|
||||||
|
"%s: Unable to bind to socket: %s",
|
||||||
|
__func__, safe_strerror(errno));
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frr_with_privs (&pimd_privs) {
|
||||||
|
rv = bind(sock, (struct sockaddr *)&sin, socklen);
|
||||||
|
}
|
||||||
|
if (rv == -1) {
|
||||||
|
flog_err_sys(EC_LIB_SOCKET,
|
||||||
|
"pim_msdp_socket bind to port %d: %s",
|
||||||
|
ntohs(sin.sin_port), safe_strerror(errno));
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set MD5 authentication. */
|
||||||
|
if (mp && mp->auth_key) {
|
||||||
|
su_peer = mp->su_peer;
|
||||||
|
frr_with_privs (&pimd_privs) {
|
||||||
|
sockopt_tcp_signature(sock, &su_peer, mp->auth_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Start listening. */
|
||||||
|
rv = listen(sock, SOMAXCONN);
|
||||||
|
if (rv == -1) {
|
||||||
|
flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s",
|
||||||
|
safe_strerror(errno));
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set socket DSCP byte */
|
||||||
|
if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
|
||||||
|
zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
|
||||||
|
sock, safe_strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_msdp_sock_auth_accept(struct event *t)
|
||||||
|
{
|
||||||
|
struct pim_msdp_peer *mp = EVENT_ARG(t);
|
||||||
|
int sock;
|
||||||
|
socklen_t sinlen;
|
||||||
|
struct sockaddr_in sin = {};
|
||||||
|
|
||||||
|
/* accept client connection. */
|
||||||
|
sinlen = sizeof(sin);
|
||||||
|
sock = accept(mp->auth_listen_sock, (struct sockaddr *)&sin, &sinlen);
|
||||||
|
if (sock == -1) {
|
||||||
|
flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)",
|
||||||
|
safe_strerror(errno));
|
||||||
|
|
||||||
|
/* Accept failed, schedule listen again. */
|
||||||
|
event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
|
||||||
|
mp->auth_listen_sock, &mp->auth_listen_ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Previous connection still going.
|
||||||
|
*
|
||||||
|
* We must wait for the user to close the previous connection in order
|
||||||
|
* to establish the new one. User can manually force that by calling
|
||||||
|
* `clear ip msdp peer A.B.C.D`.
|
||||||
|
*/
|
||||||
|
if (mp->fd != -1) {
|
||||||
|
++mp->pim->msdp.rejected_accepts;
|
||||||
|
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||||
|
flog_err(EC_PIM_MSDP_PACKET,
|
||||||
|
"msdp peer connection refused from %pI4: old connection still running",
|
||||||
|
&sin.sin_addr);
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
/* Unexpected connection, schedule listen again. */
|
||||||
|
event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
|
||||||
|
mp->auth_listen_sock, &mp->auth_listen_ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unexpected client connected. */
|
||||||
|
if (mp->peer.s_addr != sin.sin_addr.s_addr) {
|
||||||
|
++mp->pim->msdp.rejected_accepts;
|
||||||
|
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||||
|
flog_err(EC_PIM_MSDP_PACKET,
|
||||||
|
"msdp peer connection refused from %pI4",
|
||||||
|
&sin.sin_addr);
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
/* Unexpected peer, schedule listen again. */
|
||||||
|
event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
|
||||||
|
mp->auth_listen_sock, &mp->auth_listen_ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_MSDP_INTERNAL)
|
||||||
|
zlog_debug("MSDP peer %s accept success", mp->key_str);
|
||||||
|
|
||||||
|
/* Configure socket. */
|
||||||
|
mp->fd = sock;
|
||||||
|
set_nonblocking(mp->fd);
|
||||||
|
pim_msdp_update_sock_send_buffer_size(mp->fd);
|
||||||
|
pim_msdp_peer_established(mp);
|
||||||
|
|
||||||
|
/* Stop listening. */
|
||||||
|
close(mp->auth_listen_sock);
|
||||||
|
mp->auth_listen_sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp)
|
||||||
|
{
|
||||||
|
/* Clear any listening connection if it exists. */
|
||||||
|
event_cancel(&mp->auth_listen_ev);
|
||||||
|
if (mp->auth_listen_sock != -1) {
|
||||||
|
close(mp->auth_listen_sock);
|
||||||
|
mp->auth_listen_sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start new listening socket. */
|
||||||
|
mp->auth_listen_sock = _pim_msdp_sock_listen(mp->pim->vrf, mp);
|
||||||
|
if (mp->auth_listen_sock == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Listen for connections and connected only with the expected end. */
|
||||||
|
event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
|
||||||
|
mp->auth_listen_sock, &mp->auth_listen_ev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* passive peer socket accept */
|
/* passive peer socket accept */
|
||||||
static void pim_msdp_sock_accept(struct event *thread)
|
static void pim_msdp_sock_accept(struct event *thread)
|
||||||
{
|
{
|
||||||
|
@ -91,6 +277,21 @@ static void pim_msdp_sock_accept(struct event *thread)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If authentication is configured then we can not accept
|
||||||
|
* unauthenticated connections.
|
||||||
|
*/
|
||||||
|
if (mp->auth_type != MSDP_AUTH_NONE) {
|
||||||
|
++pim->msdp.rejected_accepts;
|
||||||
|
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||||
|
flog_err(EC_PIM_MSDP_PACKET,
|
||||||
|
"msdp peer unauthenticated connection refused from %pSU",
|
||||||
|
&su);
|
||||||
|
}
|
||||||
|
close(msdp_sock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (PIM_DEBUG_MSDP_INTERNAL) {
|
if (PIM_DEBUG_MSDP_INTERNAL) {
|
||||||
zlog_debug("MSDP peer %s accept success%s", mp->key_str,
|
zlog_debug("MSDP peer %s accept success%s", mp->key_str,
|
||||||
mp->fd >= 0 ? "(dup)" : "");
|
mp->fd >= 0 ? "(dup)" : "");
|
||||||
|
@ -116,9 +317,6 @@ static void pim_msdp_sock_accept(struct event *thread)
|
||||||
int pim_msdp_sock_listen(struct pim_instance *pim)
|
int pim_msdp_sock_listen(struct pim_instance *pim)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
int socklen;
|
|
||||||
struct sockaddr_in sin;
|
|
||||||
int rc;
|
|
||||||
struct pim_msdp_listener *listener = &pim->msdp.listener;
|
struct pim_msdp_listener *listener = &pim->msdp.listener;
|
||||||
|
|
||||||
if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
|
if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
|
||||||
|
@ -126,72 +324,20 @@ int pim_msdp_sock_listen(struct pim_instance *pim)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
sock = _pim_msdp_sock_listen(pim->vrf, NULL);
|
||||||
if (sock < 0) {
|
if (sock == -1)
|
||||||
flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno));
|
return -1;
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&sin, 0, sizeof(struct sockaddr_in));
|
|
||||||
sin.sin_family = AF_INET;
|
memset(&listener->su.sin, 0, sizeof(listener->su.sin));
|
||||||
sin.sin_port = htons(PIM_MSDP_TCP_PORT);
|
listener->su.sin.sin_family = AF_INET;
|
||||||
socklen = sizeof(struct sockaddr_in);
|
listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT);
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
||||||
sin.sin_len = socklen;
|
listener->su.sin.sin_len = sizeof(listener->su.sin);
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
|
|
||||||
sockopt_reuseaddr(sock);
|
|
||||||
sockopt_reuseport(sock);
|
|
||||||
|
|
||||||
if (pim->vrf->vrf_id != VRF_DEFAULT) {
|
|
||||||
struct interface *ifp =
|
|
||||||
if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id);
|
|
||||||
if (!ifp) {
|
|
||||||
flog_err(EC_LIB_INTERFACE,
|
|
||||||
"%s: Unable to lookup vrf interface: %s",
|
|
||||||
__func__, pim->vrf->name);
|
|
||||||
close(sock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (pim_socket_bind(sock, ifp)) {
|
|
||||||
flog_err_sys(EC_LIB_SOCKET,
|
|
||||||
"%s: Unable to bind to socket: %s",
|
|
||||||
__func__, safe_strerror(errno));
|
|
||||||
close(sock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
frr_with_privs(&pimd_privs) {
|
|
||||||
/* bind to well known TCP port */
|
|
||||||
rc = bind(sock, (struct sockaddr *)&sin, socklen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc < 0) {
|
|
||||||
flog_err_sys(EC_LIB_SOCKET,
|
|
||||||
"pim_msdp_socket bind to port %d: %s",
|
|
||||||
ntohs(sin.sin_port), safe_strerror(errno));
|
|
||||||
close(sock);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = listen(sock, 3 /* backlog */);
|
|
||||||
if (rc < 0) {
|
|
||||||
flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s",
|
|
||||||
safe_strerror(errno));
|
|
||||||
close(sock);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set socket DSCP byte */
|
|
||||||
if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
|
|
||||||
zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
|
|
||||||
sock, safe_strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add accept thread */
|
/* add accept thread */
|
||||||
listener->fd = sock;
|
listener->fd = sock;
|
||||||
memcpy(&listener->su, &sin, socklen);
|
|
||||||
event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
|
event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
|
||||||
&listener->thread);
|
&listener->thread);
|
||||||
|
|
||||||
|
@ -272,6 +418,14 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
|
||||||
mp->fd, safe_strerror(errno));
|
mp->fd, safe_strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set authentication (if configured). */
|
||||||
|
if (mp->auth_key) {
|
||||||
|
frr_with_privs (&pimd_privs) {
|
||||||
|
sockopt_tcp_signature(mp->fd, &mp->su_peer,
|
||||||
|
mp->auth_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect to the remote mp. */
|
/* Connect to the remote mp. */
|
||||||
return (sockunion_connect(mp->fd, &mp->su_peer,
|
return (sockunion_connect(mp->fd, &mp->su_peer,
|
||||||
htons(PIM_MSDP_TCP_PORT), 0));
|
htons(PIM_MSDP_TCP_PORT), 0));
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#ifndef PIM_MSDP_SOCKET_H
|
#ifndef PIM_MSDP_SOCKET_H
|
||||||
#define PIM_MSDP_SOCKET_H
|
#define PIM_MSDP_SOCKET_H
|
||||||
|
|
||||||
|
struct pim_msdp_peer;
|
||||||
|
|
||||||
|
int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp);
|
||||||
int pim_msdp_sock_listen(struct pim_instance *pim);
|
int pim_msdp_sock_listen(struct pim_instance *pim);
|
||||||
int pim_msdp_sock_connect(struct pim_msdp_peer *mp);
|
int pim_msdp_sock_connect(struct pim_msdp_peer *mp);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -177,6 +177,19 @@ const struct frr_yang_module_info frr_pim_info = {
|
||||||
.destroy = pim_msdp_peer_sa_filter_out_destroy,
|
.destroy = pim_msdp_peer_sa_filter_out_destroy,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type",
|
||||||
|
.cbs = {
|
||||||
|
.modify = pim_msdp_peer_authentication_type_modify,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key",
|
||||||
|
.cbs = {
|
||||||
|
.modify = pim_msdp_peer_authentication_key_modify,
|
||||||
|
.destroy = pim_msdp_peer_authentication_key_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag",
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag",
|
||||||
.cbs = {
|
.cbs = {
|
||||||
|
|
|
@ -69,6 +69,9 @@ int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args);
|
||||||
int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args);
|
int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args);
|
||||||
int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args);
|
int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args);
|
||||||
int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args);
|
int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args);
|
||||||
|
int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args);
|
||||||
|
int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args);
|
||||||
|
int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args);
|
||||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
|
||||||
struct nb_cb_create_args *args);
|
struct nb_cb_create_args *args);
|
||||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "pim_pim.h"
|
#include "pim_pim.h"
|
||||||
#include "pim_mlag.h"
|
#include "pim_mlag.h"
|
||||||
#include "pim_bfd.h"
|
#include "pim_bfd.h"
|
||||||
|
#include "pim_msdp_socket.h"
|
||||||
#include "pim_static.h"
|
#include "pim_static.h"
|
||||||
#include "pim_ssm.h"
|
#include "pim_ssm.h"
|
||||||
#include "pim_ssmpingd.h"
|
#include "pim_ssmpingd.h"
|
||||||
|
@ -1053,6 +1054,9 @@ pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address
|
||||||
nb_cb_destroy_args);
|
nb_cb_destroy_args);
|
||||||
pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create,
|
pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create,
|
||||||
nb_cb_create_args);
|
nb_cb_create_args);
|
||||||
|
pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args);
|
||||||
|
pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args);
|
||||||
|
pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args);
|
||||||
|
|
||||||
#if PIM_IPV != 6
|
#if PIM_IPV != 6
|
||||||
/*
|
/*
|
||||||
|
@ -1154,6 +1158,81 @@ int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args)
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath:
|
||||||
|
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type
|
||||||
|
*/
|
||||||
|
int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args)
|
||||||
|
{
|
||||||
|
struct pim_msdp_peer *mp;
|
||||||
|
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
/* NOTHING */
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
mp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
mp->auth_type = yang_dnode_get_enum(args->dnode, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath:
|
||||||
|
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key
|
||||||
|
*/
|
||||||
|
int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args)
|
||||||
|
{
|
||||||
|
struct pim_msdp_peer *mp;
|
||||||
|
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
if (strlen(yang_dnode_get_string(args->dnode, NULL)) >
|
||||||
|
TCP_MD5SIG_MAXKEYLEN) {
|
||||||
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"MD5 authentication key too long");
|
||||||
|
return NB_ERR_VALIDATION;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
mp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key);
|
||||||
|
mp->auth_key = XSTRDUP(MTYPE_PIM_MSDP_AUTH_KEY,
|
||||||
|
yang_dnode_get_string(args->dnode, NULL));
|
||||||
|
|
||||||
|
/* We must start listening the new authentication key now. */
|
||||||
|
if (PIM_MSDP_PEER_IS_LISTENER(mp))
|
||||||
|
pim_msdp_sock_auth_listen(mp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args)
|
||||||
|
{
|
||||||
|
struct pim_msdp_peer *mp;
|
||||||
|
|
||||||
|
switch (args->event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
/* NOTHING */
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
mp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XPath:
|
* XPath:
|
||||||
|
|
Loading…
Reference in a new issue