]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
radius: re-add support for binding radius client sockets to interfaces
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 15 Apr 2023 11:37:00 +0000 (21:37 +1000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 15 Apr 2023 11:37:00 +0000 (21:37 +1000)
src/bin/radclient.c
src/bin/radsnmp.c
src/lib/util/socket.c
src/lib/util/socket.h
src/listen/control/radmin.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_logtee/rlm_logtee.c
src/modules/rlm_radius/rlm_radius_udp.c
src/modules/rlm_tacacs/rlm_tacacs_tcp.c

index 8b1d9e9f75f81236d4dd865dc753392bbff521ef..22829774a65d3926607f8f15e2ed5cb5579568b2 100644 (file)
@@ -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;
index 578deb8ca0661a10bc32273d039a7e23c831f73b..fce5f121c0ebb76ad492eb45df3929579ceadd2f 100644 (file)
@@ -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) {
index 46e24473183146e120a762ca451c5a25b121f913..e6fc0fd40ca85174c24eea4ca53d6ce89804c98f 100644 (file)
 #include <freeradius-devel/util/cap.h>
 
 #include <fcntl.h>
-
-#ifndef SO_BINDTODEVICE
-#endif
-
+#include <sys/socket.h>
 #include <ifaddrs.h>
 
 /** 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.
         */
index 8a50ea8cc0e7413c0cca28299839a05e5d72ef81..2a59f451a2056f7c145e39a6333d0342c39f71e7 100644 (file)
@@ -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);
index 3f8ab61a296994b276efb68adce24e90681a261e..f952eb659911542796dda91323c6e53495e5ee7f 100644 (file)
@@ -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));
index 7acda9ffddf73750ad7dd8e2a91d857bdca01172..cfcedbebacaf0fd0692bc5ecb0bb282645c8ed53 100644 (file)
@@ -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;
index a8d750cdb8882e55c5a3d0b9514ad1803f95bb0f..f6efe42b0a05ac1f336e2d9f3effbc08eaa06de3 100644 (file)
@@ -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;
 
index 5d6bd6e1f78eda497bc680f7716b33364d1a7d7c..41630f3de1f220dbfc8c9c9a440e7a269b6a2ffb 100644 (file)
@@ -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:
index 2b0d14ff4127c1b0e133e874d00af4d011b45b82..bb73ad7d46ba78b477cdfae6032956f9bfb4d86a 100644 (file)
@@ -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);