diff options
author | Daniel Baumann <daniel@debian.org> | 2024-11-17 07:11:26 +0100 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-11-17 07:11:26 +0100 |
commit | d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6 (patch) | |
tree | 705ea89e798053f9c227b85512bc9f5b437b0093 /pimd/pim_msdp_socket.c | |
parent | Releasing debian version 10.1.1-3. (diff) | |
download | frr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.tar.xz frr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.zip |
Merging upstream version 10.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'pimd/pim_msdp_socket.c')
-rw-r--r-- | pimd/pim_msdp_socket.c | 280 |
1 files changed, 217 insertions, 63 deletions
diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index fe8d5e93..2fb0bb87 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -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 */ static void pim_msdp_sock_accept(struct event *thread) { @@ -91,6 +277,21 @@ static void pim_msdp_sock_accept(struct event *thread) 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) { zlog_debug("MSDP peer %s accept success%s", mp->key_str, 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 sock; - int socklen; - struct sockaddr_in sin; - int rc; struct pim_msdp_listener *listener = &pim->msdp.listener; if (pim->msdp.flags & PIM_MSDPF_LISTENER) { @@ -126,72 +324,20 @@ int pim_msdp_sock_listen(struct pim_instance *pim) return 0; } - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno)); - return sock; - } + sock = _pim_msdp_sock_listen(pim->vrf, NULL); + if (sock == -1) + return -1; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons(PIM_MSDP_TCP_PORT); - socklen = sizeof(struct sockaddr_in); + + memset(&listener->su.sin, 0, sizeof(listener->su.sin)); + listener->su.sin.sin_family = AF_INET; + listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT); #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 */ - 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 */ listener->fd = sock; - memcpy(&listener->su, &sin, socklen); event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock, &listener->thread); @@ -272,6 +418,14 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) 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. */ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0)); |