From: Arran Cudbard-Bell Date: Sat, 15 Apr 2023 11:37:00 +0000 (+1000) Subject: radius: re-add support for binding radius client sockets to interfaces X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a285a9335288917e775957bef5a2c4a629f59889;p=thirdparty%2Ffreeradius-server.git radius: re-add support for binding radius client sockets to interfaces --- diff --git a/src/bin/radclient.c b/src/bin/radclient.c index 8b1d9e9f75f..22829774a65 100644 --- a/src/bin/radclient.c +++ b/src/bin/radclient.c @@ -933,7 +933,7 @@ static int send_one_packet(rc_request_t *request) int mysockfd; if (ipproto == IPPROTO_TCP) { - mysockfd = fr_socket_client_tcp(NULL, + mysockfd = fr_socket_client_tcp(NULL, NULL, &request->packet->socket.inet.dst_ipaddr, request->packet->socket.inet.dst_port, false); if (mysockfd < 0) { @@ -1774,7 +1774,7 @@ int main(int argc, char **argv) if (client_port == 0) client_port = request->packet->socket.inet.src_port; if (ipproto == IPPROTO_TCP) { - sockfd = fr_socket_client_tcp(NULL, &server_ipaddr, server_port, false); + sockfd = fr_socket_client_tcp(NULL, NULL, &server_ipaddr, server_port, false); if (sockfd < 0) { ERROR("Failed opening socket"); return -1; diff --git a/src/bin/radsnmp.c b/src/bin/radsnmp.c index 578deb8ca06..fce5f121c0e 100644 --- a/src/bin/radsnmp.c +++ b/src/bin/radsnmp.c @@ -1118,12 +1118,12 @@ int main(int argc, char **argv) switch (conf->proto) { case IPPROTO_TCP: - sockfd = fr_socket_client_tcp(NULL, &conf->server_ipaddr, conf->server_port, true); + sockfd = fr_socket_client_tcp(NULL, NULL, &conf->server_ipaddr, conf->server_port, true); break; default: case IPPROTO_UDP: - sockfd = fr_socket_client_udp(NULL, NULL, &conf->server_ipaddr, conf->server_port, true); + sockfd = fr_socket_client_udp(NULL, NULL, NULL, &conf->server_ipaddr, conf->server_port, true); break; } if (sockfd < 0) { diff --git a/src/lib/util/socket.c b/src/lib/util/socket.c index 46e24473183..e6fc0fd40ca 100644 --- a/src/lib/util/socket.c +++ b/src/lib/util/socket.c @@ -34,10 +34,7 @@ #include #include - -#ifndef SO_BINDTODEVICE -#endif - +#include #include /** Resolve a named service to a port @@ -312,6 +309,31 @@ int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async) } #endif /* WITH_SYS_UN_H */ +static inline CC_HINT(always_inline) int socket_bind_ifname(int sockfd, char const *ifname) +{ +#if defined(SO_BINDTODEVICE) + if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { + fr_strerror_printf("Failed binding socket to %s: %s", ifname, fr_syserror(errno)); + return -1; + } +#elif defined(IP_BOUND_IF) + { + int idx = if_nametoindex(ifname); + if (idx == 0) { + error: + fr_strerror_printf("Failed binding socket to %s: %s", ifname, fr_syserror(errno)); + return -1; + } + if (unlikely(setsockopt(sockfd, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)) < 0)) goto error; + } +#else + fr_strerror_const("Binding sockets to interfaces not supported on this platform"); + return -1; +#endif + + return 0; +} + /** Establish a connected UDP socket * * Connected UDP sockets can be used with write(), unlike unconnected sockets @@ -319,7 +341,7 @@ int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async) * * The following code demonstrates using this function with a connection timeout: @code {.c} - sockfd = fr_socket_client_udp(NULL, NULL, ipaddr, port, true); + sockfd = fr_socket_client_udp(NULL, NULL, NULL, ipaddr, port, true); if (sockfd < 0) { fr_perror(); fr_exit_now(1); @@ -334,18 +356,20 @@ int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async) if (fr_blocking(sockfd) < 0) goto error; @endcode * + * @param[in] ifname If non-NULL, bind the socket to this interface. * @param[in,out] src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific - * address. If non-null, the bound IP is copied here, too. - * @param[out] src_port The source port we were bound to, may be NULL. - * @param dst_ipaddr Where to send datagrams. - * @param dst_port Where to send datagrams. - * @param async Whether to set the socket to nonblocking, allowing use of - * #fr_socket_wait_for_connect. + * address. If non-null, the bound IP is copied here, too. + * @param[out] src_port The source port we were bound to, may be NULL. + * @param[in] dst_ipaddr Where to send datagrams. + * @param[in] dst_port Where to send datagrams. + * @param[in] async Whether to set the socket to nonblocking, allowing use of + * #fr_socket_wait_for_connect. * @return * - FD on success. * - -1 on failure. */ -int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async) +int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, + fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async) { int sockfd; struct sockaddr_storage salocal; @@ -365,6 +389,11 @@ int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_ return -1; } + /* + * Bind to a specific interface + */ + if (ifname && (socket_bind_ifname(sockfd, ifname) < 0)) goto error; + /* * Allow the caller to bind us to a specific source IP. */ @@ -454,7 +483,7 @@ int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_ * * The following code demonstrates using this function with a connection timeout: @code {.c} - sockfd = fr_socket_client_tcp(NULL, ipaddr, port, true); + sockfd = fr_socket_client_tcp(NULL, NULL, ipaddr, port, true); if (sockfd < 0) { fr_perror(); fr_exit_now(1); @@ -469,6 +498,7 @@ int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_ if (fr_blocking(sockfd) < 0) goto error; @endcode * + * @param[in] ifname If non-NULL, bind the socket to this interface. * @param src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific * address. * @param dst_ipaddr Where to connect to. @@ -479,7 +509,8 @@ int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_ * - FD on success * - -1 on failure. */ -int fr_socket_client_tcp(fr_ipaddr_t const *src_ipaddr, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async) +int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t const *src_ipaddr, + fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async) { int sockfd; struct sockaddr_storage salocal; @@ -494,10 +525,16 @@ int fr_socket_client_tcp(fr_ipaddr_t const *src_ipaddr, fr_ipaddr_t const *dst_i } if (async && (fr_nonblock(sockfd) < 0)) { + error: close(sockfd); return -1; } + /* + * Bind to a specific interface + */ + if (ifname && (socket_bind_ifname(sockfd, ifname) < 0)) goto error; + /* * Allow the caller to bind us to a specific source IP. */ diff --git a/src/lib/util/socket.h b/src/lib/util/socket.h index 8a50ea8cc0e..2a59f451a20 100644 --- a/src/lib/util/socket.h +++ b/src/lib/util/socket.h @@ -299,11 +299,11 @@ static inline fr_socket_t *fr_socket_addr_alloc_inet_dst(TALLOC_CTX *ctx, int pr int fr_socket_client_unix(char const *path, bool async); -int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t const *dst_ipaddr, - uint16_t dst_port, bool async); +int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, + fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async); -int fr_socket_client_tcp(fr_ipaddr_t const *src_ipaddr, fr_ipaddr_t const *dst_ipaddr, - uint16_t dst_port, bool async); +int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t const *src_ipaddr, + fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async); int fr_socket_wait_for_connect(int sockfd, fr_time_delta_t timeout); int fr_socket_server_udp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async); diff --git a/src/listen/control/radmin.c b/src/listen/control/radmin.c index 3f8ab61a296..f952eb65991 100644 --- a/src/listen/control/radmin.c +++ b/src/listen/control/radmin.c @@ -202,7 +202,7 @@ static int client_socket(char const *server) fr_exit_now(EXIT_FAILURE); } - fd = fr_socket_client_tcp(NULL, &ipaddr, port, false); + fd = fr_socket_client_tcp(NULL, NULL, &ipaddr, port, false); if (fd < 0) { fprintf(stderr, "%s: Failed opening socket %s: %s\n", progname, server, fr_syserror(errno)); diff --git a/src/modules/rlm_linelog/rlm_linelog.c b/src/modules/rlm_linelog/rlm_linelog.c index 7acda9ffddf..cfcedbebaca 100644 --- a/src/modules/rlm_linelog/rlm_linelog.c +++ b/src/modules/rlm_linelog/rlm_linelog.c @@ -219,7 +219,7 @@ static void *mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t ti case LINELOG_DST_TCP: DEBUG2("Opening TCP connection to %pV:%u", fr_box_ipaddr(inst->tcp.dst_ipaddr), inst->tcp.port); - sockfd = fr_socket_client_tcp(NULL, &inst->tcp.dst_ipaddr, inst->tcp.port, true); + sockfd = fr_socket_client_tcp(NULL, NULL, &inst->tcp.dst_ipaddr, inst->tcp.port, true); if (sockfd < 0) { PERROR("Failed opening TCP socket"); return NULL; @@ -229,7 +229,7 @@ static void *mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t ti case LINELOG_DST_UDP: DEBUG2("Opening UDP connection to %pV:%u", fr_box_ipaddr(inst->udp.dst_ipaddr), inst->udp.port); - sockfd = fr_socket_client_udp(NULL, NULL, &inst->udp.dst_ipaddr, inst->udp.port, true); + sockfd = fr_socket_client_udp(NULL, NULL, NULL, &inst->udp.dst_ipaddr, inst->udp.port, true); if (sockfd < 0) { PERROR("Failed opening UDP socket"); return NULL; diff --git a/src/modules/rlm_logtee/rlm_logtee.c b/src/modules/rlm_logtee/rlm_logtee.c index a8d750cdb88..f6efe42b0a0 100644 --- a/src/modules/rlm_logtee/rlm_logtee.c +++ b/src/modules/rlm_logtee/rlm_logtee.c @@ -404,14 +404,14 @@ static fr_connection_state_t _logtee_conn_init(void **h_out, fr_connection_t *co case LOGTEE_DST_TCP: DEBUG2("Opening TCP connection to %pV:%u", fr_box_ipaddr(inst->tcp.dst_ipaddr), inst->tcp.port); - fd = fr_socket_client_tcp(NULL, &inst->tcp.dst_ipaddr, inst->tcp.port, true); + fd = fr_socket_client_tcp(NULL, NULL, &inst->tcp.dst_ipaddr, inst->tcp.port, true); if (fd < 0) return FR_CONNECTION_STATE_FAILED; break; case LOGTEE_DST_UDP: DEBUG2("Opening UDP connection to %pV:%u", fr_box_ipaddr(inst->udp.dst_ipaddr), inst->udp.port); - fd = fr_socket_client_udp(NULL, NULL, &inst->udp.dst_ipaddr, inst->udp.port, true); + fd = fr_socket_client_udp(NULL, NULL, NULL, &inst->udp.dst_ipaddr, inst->udp.port, true); if (fd < 0) return FR_CONNECTION_STATE_FAILED; break; diff --git a/src/modules/rlm_radius/rlm_radius_udp.c b/src/modules/rlm_radius/rlm_radius_udp.c index 5d6bd6e1f78..41630f3de1f 100644 --- a/src/modules/rlm_radius/rlm_radius_udp.c +++ b/src/modules/rlm_radius/rlm_radius_udp.c @@ -756,7 +756,8 @@ static fr_connection_state_t conn_init(void **h_out, fr_connection_t *conn, void /* * Open the outgoing socket. */ - fd = fr_socket_client_udp(&h->src_ipaddr, &h->src_port, &h->inst->dst_ipaddr, h->inst->dst_port, true); + fd = fr_socket_client_udp(h->inst->interface, &h->src_ipaddr, &h->src_port, + &h->inst->dst_ipaddr, h->inst->dst_port, true); if (fd < 0) { PERROR("%s - Failed opening socket", h->module_name); fail: diff --git a/src/modules/rlm_tacacs/rlm_tacacs_tcp.c b/src/modules/rlm_tacacs/rlm_tacacs_tcp.c index 2b0d14ff412..bb73ad7d46b 100644 --- a/src/modules/rlm_tacacs/rlm_tacacs_tcp.c +++ b/src/modules/rlm_tacacs/rlm_tacacs_tcp.c @@ -282,7 +282,7 @@ static fr_connection_state_t conn_init(void **h_out, fr_connection_t *conn, void /* * Open the outgoing socket. */ - fd = fr_socket_client_tcp(&h->src_ipaddr, &h->inst->dst_ipaddr, h->inst->dst_port, true); + fd = fr_socket_client_tcp(NULL, &h->src_ipaddr, &h->inst->dst_ipaddr, h->inst->dst_port, true); if (fd < 0) { PERROR("%s - Failed opening socket", h->module_name); talloc_free(h);