]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Use the existing bind function for binding client sockets to interfaces, ipaddrs...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 16 Apr 2023 09:20:32 +0000 (19:20 +1000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 16 Apr 2023 09:20:32 +0000 (19:20 +1000)
17 files changed:
src/bin/dhcpclient.c
src/bin/radclient.c
src/lib/util/socket.c
src/lib/util/socket.h
src/lib/util/udp_queue.c
src/listen/bfd/proto_bfd_udp.c
src/listen/dhcpv4/proto_dhcpv4_udp.c
src/listen/dhcpv6/proto_dhcpv6_udp.c
src/listen/dns/proto_dns_udp.c
src/listen/radius/#proto_radius_tcp.c#
src/listen/radius/proto_radius_tcp.c
src/listen/radius/proto_radius_udp.c
src/listen/tacacs/proto_tacacs_tcp.c
src/listen/vmps/proto_vmps_udp.c
src/modules/rlm_icmp/rlm_icmp.c
src/tests/util/radius1_test.c
src/tests/util/radius_schedule_test.c

index 30b969ad0cfd73debcbba032117502a8ebe3fdb2..42293bdcf129ac202cdf564944c06032e32216b5 100644 (file)
@@ -366,7 +366,7 @@ static int send_with_socket(fr_radius_packet_t **reply, fr_radius_packet_t *requ
                        return -1;
                }
 
-               if (fr_socket_bind(sockfd, &request->socket.inet.src_ipaddr, &request->socket.inet.src_port, NULL) < 0) {
+               if (fr_socket_bind(sockfd, NULL, &request->socket.inet.src_ipaddr, &request->socket.inet.src_port) < 0) {
                        ERROR("Error binding socket - %s", fr_strerror());
                        return -1;
                }
index 22829774a65d3926607f8f15e2ed5cb5579568b2..d51f9a52c1a545162f87aba7c603a35523eba847 100644 (file)
@@ -949,7 +949,7 @@ static int send_one_packet(rc_request_t *request)
                                        return -1;
                                }
 
-                               if (fr_socket_bind(mysockfd, &client_ipaddr, &port, NULL) < 0) {
+                               if (fr_socket_bind(mysockfd, NULL, &client_ipaddr, &port) < 0) {
                                        fr_perror("Error binding socket");
                                        return -1;
                                }
@@ -1787,7 +1787,7 @@ int main(int argc, char **argv)
                        return -1;
                }
 
-               if (fr_socket_bind(sockfd, &client_ipaddr, &client_port, NULL) < 0) {
+               if (fr_socket_bind(sockfd, NULL, &client_ipaddr, &client_port) < 0) {
                        fr_perror("Error binding socket");
                        return -1;
                }
@@ -1800,7 +1800,7 @@ int main(int argc, char **argv)
                        return -1;
                }
 
-               if (fr_socket_bind(coafd, &client_ipaddr, &coa_port, NULL) < 0) {
+               if (fr_socket_bind(coafd, NULL, &client_ipaddr, &coa_port) < 0) {
                        fr_perror("Error binding socket");
                        return -1;
                }
index e6fc0fd40ca85174c24eea4ca53d6ce89804c98f..7c9aea7b158a0dcc18c0c16ef979759b3eaedc8a 100644 (file)
@@ -209,6 +209,255 @@ static int socket_dont_fragment(UNUSED int sockfd, UNUSED int af)
 }
 #endif /* lots of things */
 
+/** Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
+ *
+ * Use one of:
+ * - fr_socket_server_udp - for non-connected socket.
+ * - fr_socket_server_tcp
+ * ...to open a file descriptor, then call this function to bind the socket to an IP address.
+ *
+ * @param[in] sockfd           the socket which opened by fr_socket_server_*.
+ * @param[in] ifname           to bind to.
+ * @param[in,out] src_ipaddr   The IP address to bind to.  Will be updated to the IP address
+ *                             that was actually bound to. Pass NULL to just bind to an interface.
+ * @param[in] src_port         the port to bind to.  NULL if any port is allowed.
+
+ * @return
+ *     - 0 on success
+ *     - -1 on failure.
+ */
+int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
+{
+       int                             ret;
+       uint16_t                        my_port = 0;
+       fr_ipaddr_t                     my_ipaddr;
+       struct sockaddr_storage         salocal;
+       socklen_t                       salen;
+
+       /*
+        *      Clear the thread local error stack as we may
+        *      push multiple errors onto the stack, and this
+        *      is likely to be the function which returns
+        *      the "original" error.
+        */
+       fr_strerror_clear();
+
+       if (src_port) my_port = *src_port;
+       if (src_ipaddr) {
+               my_ipaddr = *src_ipaddr;
+       } else {
+               my_ipaddr = (fr_ipaddr_t) {
+                       .af = AF_UNSPEC
+               };
+       }
+
+#ifdef HAVE_CAPABILITY_H
+       /*
+        *      If we're binding to a special port as non-root, then
+        *      check capabilities.  If we're root, we already have
+        *      equivalent capabilities so we don't need to check.
+        */
+       if (src_port && (*src_port < 1024) && (geteuid() != 0)) {
+               (void)fr_cap_enable(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE);       /* Sets error on failure, which will be seen if the bind fails */
+       }
+#endif
+
+       /*
+        *      Bind to a device BEFORE touching IP addresses.
+        */
+       if (ifname) {
+#ifdef HAVE_NET_IF_H
+               uint32_t scope_id;
+
+               scope_id = if_nametoindex(ifname);
+               if (!scope_id) {
+                       fr_strerror_printf_push("Failed finding interface %s: %s", ifname, fr_syserror(errno));
+                       return -1;
+               }
+
+               /*
+                *      If the scope ID hasn't already been set, then
+                *      set it.  This allows us to get the scope from the interface name.
+                */
+               if ((my_ipaddr.scope_id != 0) && (scope_id != my_ipaddr.scope_id)) {
+                       fr_strerror_printf_push("Cannot bind to interface %s: Socket is already bound "
+                                               "to another interface", ifname);
+                       return -1;
+               }
+#endif
+
+#ifdef SO_BINDTODEVICE
+               /*
+                *      The caller didn't specify a scope_id, but we
+                *      have one from above.  Call "bind to device",
+                *      and set the scope_id.
+                */
+               if (!my_ipaddr.scope_id) {
+                       /*
+                        *      The internet hints that CAP_NET_RAW
+                        *      is required to use SO_BINDTODEVICE.
+                        *
+                        *      This function also sets fr_strerror()
+                        *      on failure, which will be seen if the
+                        *      bind fails.  If the bind succeeds,
+                        *      then we don't really care that the
+                        *      capability change has failed.  We must
+                        *      already have that capability.
+                        */
+#ifdef HAVE_CAPABILITY_H
+                       (void)fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE);
+#endif
+                       ret = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+                       if (ret < 0) {
+                               fr_strerror_printf_push("Bind failed on interface %s: %s",
+                                                       ifname, fr_syserror(errno));
+                               return -1;
+                       } /* else it worked. */
+
+                       /*
+                        *      Set the scope ID.
+                        */
+                       my_ipaddr.scope_id = scope_id;
+               }
+               /*
+                *      SO_BINDTODEVICE succeeded, so we're always
+                *      bound to the socket.
+                */
+
+#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
+               {
+                       struct ifaddrs *list = NULL;
+                       bool bound = false;
+
+                       /*
+                        *      Troll through all interfaces to see if there's
+                        */
+                       if (getifaddrs(&list) == 0) {
+                               struct ifaddrs *i;
+
+                               for (i = list; i != NULL; i = i->ifa_next) {
+                                       if (i->ifa_addr && i->ifa_name && (strcmp(i->ifa_name, ifname) == 0)) {
+                                               /*
+                                                *      IPv4, and there's either no src_ip, OR src_ip is INADDR_ANY,
+                                                *      it's a match.
+                                                *
+                                                *      We also update my_ipaddr to point to this particular IP,
+                                                *      so that we can later bind() to it.  This gets us the same
+                                                *      effect as SO_BINDTODEVICE.
+                                                */
+                                               if ((i->ifa_addr->sa_family == AF_INET) &&
+                                                   (!src_ipaddr || fr_ipaddr_is_inaddr_any(src_ipaddr))) {
+                                                       (void) fr_ipaddr_from_sockaddr(&my_ipaddr, NULL,
+                                                                                      (struct sockaddr_storage *) i->ifa_addr,
+                                                                                      sizeof(struct sockaddr_in));
+                                                       my_ipaddr.scope_id = scope_id;
+                                                       bound = true;
+                                                       break;
+                                               }
+
+                                               /*
+                                                *      The caller specified a source IP, and we find a matching
+                                                *      address family.  Allow it.
+                                                *
+                                                *      Note that we do NOT check for matching IPs here.  If we did,
+                                                *      then binding to an interface and the *wrong* IP would get us
+                                                *      a "bind to device is unsupported" message.
+                                                *
+                                                *      Instead we say "yes, we found a matching interface", and then
+                                                *      allow the bind() call below to run.  If that fails, we get a
+                                                *      "Can't assign requested address" error, which is more informative.
+                                                */
+                                               if (src_ipaddr && (src_ipaddr->af == i->ifa_addr->sa_family)) {
+                                                       my_ipaddr.scope_id = scope_id;
+                                                       bound = true;
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               freeifaddrs(list);
+
+                               if (!bound) {
+                                       /*
+                                        *      IPv4: no link local addresses,
+                                        *      and no bind to device.
+                                        */
+                                       fr_strerror_printf_push("Bind to interface %s failed: Unable to match "
+                                                               "interface with the given IP address.", ifname);
+                                       return -1;
+                               }
+                       } else {
+                               fr_strerror_printf_push("Bind to interface %s failed, unable to get list of interfaces: %s",
+                                                       ifname, fr_syserror(errno));
+                               return -1;
+                       }
+               }
+#endif
+       } /* else no interface was passed in */
+
+       /*
+        *      Don't bind to an IP address if there's no src IP address.
+        */
+       if (my_ipaddr.af == AF_UNSPEC) goto done;
+
+       /*
+        *      Set up sockaddr stuff.
+        */
+       if (fr_ipaddr_to_sockaddr(&salocal, &salen, &my_ipaddr, my_port) < 0) return -1;
+
+       ret = bind(sockfd, (struct sockaddr *) &salocal, salen);
+       if (ret < 0) {
+               fr_strerror_printf_push("Bind failed with source address %pV:%pV on interface %s: %s",
+                                       src_ipaddr ? fr_box_ipaddr(*src_ipaddr) : fr_box_strvalue("*"),
+                                       src_port ? fr_box_int16(*src_port) : fr_box_strvalue("*"),
+                                       ifname ? ifname : "*",
+                                       fr_syserror(errno));
+               return ret;
+       }
+
+       if (!src_port) goto done;
+
+       /*
+        *      FreeBSD jail issues.  We bind to 0.0.0.0, but the
+        *      kernel instead binds us to a 1.2.3.4.  So once the
+        *      socket is bound, ask it what it's IP address is.
+        *
+        *      @todo - Uh... we don't update src_ipaddr with the new
+        *      IP address.  This means that we don't tell the caller
+        *      what IP address we're bound to.  That seems wrong.
+        */
+       salen = sizeof(salocal);
+       memset(&salocal, 0, salen);
+       if (getsockname(sockfd, (struct sockaddr *) &salocal, &salen) < 0) {
+               fr_strerror_printf_push("Failed getting socket name: %s", fr_syserror(errno));
+               return -1;
+       }
+
+       if (fr_ipaddr_from_sockaddr(&my_ipaddr, &my_port, &salocal, salen) < 0) return -1;
+       *src_port = my_port;
+       *src_ipaddr = my_ipaddr;
+
+done:
+#ifdef HAVE_CAPABILITY_H
+       /*
+        *      Clear any errors we may have produced in the
+        *      capabilities check.
+        */
+       fr_strerror_clear();
+#endif
+       return 0;
+}
+
 #ifdef HAVE_SYS_UN_H
 /** Open a Unix socket
  *
@@ -389,32 +638,6 @@ int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *
                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.
-        */
-       if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) {
-               /*
-                *      Ensure don't fragment bit is set
-                */
-               if (socket_dont_fragment(sockfd, src_ipaddr->af) < 0) goto error;
-
-               if (fr_ipaddr_to_sockaddr(&salocal, &salen, src_ipaddr, 0) < 0) {
-                       close(sockfd);
-                       return -1;
-               }
-
-               if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
-                       fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno));
-                       close(sockfd);
-                       return -1;
-               }
-       }
-
        /*
         *      Although we ignore SIGPIPE, some operating systems
         *      like BSD and OSX ignore the ignoring.
@@ -431,27 +654,7 @@ int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *
        }
 #endif
 
-       /*
-        *      FreeBSD jail issues.  We bind to 0.0.0.0, but the
-        *      kernel instead binds us to a 1.2.3.4.  So once the
-        *      socket is bound, ask it what it's IP address is.
-        *
-        *      If the caller asks for only one, well, too bad.
-        */
-       if (src_ipaddr && src_port) {
-               salen = sizeof(salocal);
-               memset(&salocal, 0, salen);
-               if (getsockname(sockfd, (struct sockaddr *) &salocal, &salen) < 0) {
-                       close(sockfd);
-                       fr_strerror_printf("Failed getting socket name: %s", fr_syserror(errno));
-                       return -1;
-               }
-
-               if (fr_ipaddr_from_sockaddr(src_ipaddr, src_port, &salocal, salen) < 0) {
-                       close(sockfd);
-                       return -1;
-               }
-       }
+       if (unlikely(fr_socket_bind(sockfd, ifname, src_ipaddr, src_port) < 0)) goto error;
 
        /*
         *      And now get our destination
@@ -509,7 +712,7 @@ int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *
  *     - FD on success
  *     - -1 on failure.
  */
-int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t const *src_ipaddr,
+int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr,
                         fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
 {
        int                     sockfd;
@@ -530,26 +733,7 @@ int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t const *src_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.
-        */
-       if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) {
-               if (fr_ipaddr_to_sockaddr(&salocal, &salen, src_ipaddr, 0) < 0) {
-                       close(sockfd);
-                       return -1;
-               }
-
-               if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
-                       fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno));
-                       close(sockfd);
-                       return -1;
-               }
-       }
+       if (unlikely(fr_socket_bind(sockfd, ifname, src_ipaddr, NULL) < 0)) goto error;
 
        if (fr_ipaddr_to_sockaddr(&salocal, &salen, dst_ipaddr, dst_port) < 0) {
                close(sockfd);
@@ -837,241 +1021,3 @@ int fr_socket_server_tcp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char
 
        return sockfd;
 }
-
-/** Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
- *
- * Use one of:
- * - fr_socket_client_udp - for a connected socket.
- * - fr_socket_server_udp - for non-connected socket.
- * - fr_socket_server_tcp
- * ...to open a file descriptor, then call this function to bind the socket to an IP address.
- *
- * @param[in] sockfd           the socket which opened by fr_socket_server_*.
- * @param[in,out] src_ipaddr   The IP address to bind to.  NULL to just bind to an interface.
- * @param[in] src_port         the port to bind to.  NULL if any port is allowed.
- * @param[in] interface                to bind to.
- * @return
- *     - 0 on success
- *     - -1 on failure.
- */
-int fr_socket_bind(int sockfd, fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *interface)
-{
-       int                             ret;
-       uint16_t                        my_port = 0;
-       fr_ipaddr_t                     my_ipaddr;
-       struct sockaddr_storage         salocal;
-       socklen_t                       salen;
-
-       /*
-        *      Clear the thread local error stack as we may
-        *      push multiple errors onto the stack, and this
-        *      is likely to be the function which returns
-        *      the "original" error.
-        */
-       fr_strerror_clear();
-
-       if (src_port) my_port = *src_port;
-       if (src_ipaddr) {
-               my_ipaddr = *src_ipaddr;
-       } else {
-               my_ipaddr = (fr_ipaddr_t) {
-                       .af = AF_UNSPEC
-               };
-       }
-
-#ifdef HAVE_CAPABILITY_H
-       /*
-        *      If we're binding to a special port as non-root, then
-        *      check capabilities.  If we're root, we already have
-        *      equivalent capabilities so we don't need to check.
-        */
-       if (src_port && (*src_port < 1024) && (geteuid() != 0)) {
-               (void)fr_cap_enable(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE);       /* Sets error on failure, which will be seen if the bind fails */
-       }
-#endif
-
-       /*
-        *      Bind to a device BEFORE touching IP addresses.
-        */
-       if (interface) {
-#ifdef HAVE_NET_IF_H
-               uint32_t scope_id;
-
-               scope_id = if_nametoindex(interface);
-               if (!scope_id) {
-                       fr_strerror_printf_push("Failed finding interface %s: %s",
-                                               interface, fr_syserror(errno));
-                       return -1;
-               }
-
-               /*
-                *      If the scope ID hasn't already been set, then
-                *      set it.  This allows us to get the scope from the interface name.
-                */
-               if ((my_ipaddr.scope_id != 0) && (scope_id != my_ipaddr.scope_id)) {
-                       fr_strerror_printf_push("Cannot bind to interface %s: Socket is already bound "
-                                               "to another interface", interface);
-                       return -1;
-               }
-#endif
-
-#ifdef SO_BINDTODEVICE
-               /*
-                *      The caller didn't specify a scope_id, but we
-                *      have one from above.  Call "bind to device",
-                *      and set the scope_id.
-                */
-               if (!my_ipaddr.scope_id) {
-                       /*
-                        *      The internet hints that CAP_NET_RAW
-                        *      is required to use SO_BINDTODEVICE.
-                        *
-                        *      This function also sets fr_strerror()
-                        *      on failure, which will be seen if the
-                        *      bind fails.  If the bind succeeds,
-                        *      then we don't really care that the
-                        *      capability change has failed.  We must
-                        *      already have that capability.
-                        */
-#ifdef HAVE_CAPABILITY_H
-                       (void)fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE);
-#endif
-                       ret = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface));
-                       if (ret < 0) {
-                               fr_strerror_printf_push("Bind failed on interface %s: %s",
-                                                       interface, fr_syserror(errno));
-                               return -1;
-                       } /* else it worked. */
-
-                       /*
-                        *      Set the scope ID.
-                        */
-                       my_ipaddr.scope_id = scope_id;
-               }
-               /*
-                *      SO_BINDTODEVICE succeeded, so we're always
-                *      bound to the socket.
-                */
-
-#else
-               {
-                       struct ifaddrs *list = NULL;
-                       bool bound = false;
-
-                       /*
-                        *      Troll through all interfaces to see if there's
-                        */
-                       if (getifaddrs(&list) == 0) {
-                               struct ifaddrs *i;
-
-                               for (i = list; i != NULL; i = i->ifa_next) {
-                                       if (i->ifa_addr && i->ifa_name && (strcmp(i->ifa_name, interface) == 0)) {
-                                               /*
-                                                *      IPv4, and there's either no src_ip, OR src_ip is INADDR_ANY,
-                                                *      it's a match.
-                                                *
-                                                *      We also update my_ipaddr to point to this particular IP,
-                                                *      so that we can later bind() to it.  This gets us the same
-                                                *      effect as SO_BINDTODEVICE.
-                                                */
-                                               if ((i->ifa_addr->sa_family == AF_INET) &&
-                                                   (!src_ipaddr || fr_ipaddr_is_inaddr_any(src_ipaddr))) {
-                                                       (void) fr_ipaddr_from_sockaddr(&my_ipaddr, NULL,
-                                                                                      (struct sockaddr_storage *) i->ifa_addr,
-                                                                                      sizeof(struct sockaddr_in));
-                                                       my_ipaddr.scope_id = scope_id;
-                                                       bound = true;
-                                                       break;
-                                               }
-
-                                               /*
-                                                *      The caller specified a source IP, and we find a matching
-                                                *      address family.  Allow it.
-                                                *
-                                                *      Note that we do NOT check for matching IPs here.  If we did,
-                                                *      then binding to an interface and the *wrong* IP would get us
-                                                *      a "bind to device is unsupported" message.
-                                                *
-                                                *      Instead we say "yes, we found a matching interface", and then
-                                                *      allow the bind() call below to run.  If that fails, we get a
-                                                *      "Can't assign requested address" error, which is more informative.
-                                                */
-                                               if (src_ipaddr && (src_ipaddr->af == i->ifa_addr->sa_family)) {
-                                                       my_ipaddr.scope_id = scope_id;
-                                                       bound = true;
-                                                       break;
-                                               }
-                                       }
-                               }
-
-                               freeifaddrs(list);
-
-                               if (!bound) {
-                                       /*
-                                        *      IPv4: no link local addresses,
-                                        *      and no bind to device.
-                                        */
-                                       fr_strerror_printf_push("Bind to interface %s failed: Unable to match "
-                                                               "interface with the given IP address.", interface);
-                                       return -1;
-                               }
-                       } else {
-                               fr_strerror_printf_push("Bind to interface %s failed, unable to get list of interfaces: %s",
-                                                       interface, fr_syserror(errno));
-                               return -1;
-                       }
-               }
-#endif
-       } /* else no interface was passed in */
-
-       /*
-        *      Don't bind to an IP address if there's no src IP address.
-        */
-       if (my_ipaddr.af == AF_UNSPEC) goto done;
-
-       /*
-        *      Set up sockaddr stuff.
-        */
-       if (fr_ipaddr_to_sockaddr(&salocal, &salen, &my_ipaddr, my_port) < 0) return -1;
-
-       ret = bind(sockfd, (struct sockaddr *) &salocal, salen);
-       if (ret < 0) {
-               fr_strerror_printf_push("Bind failed with source address %pV:%pV on interface %s: %s",
-                                       src_ipaddr ? fr_box_ipaddr(*src_ipaddr) : fr_box_strvalue("*"),
-                                       src_port ? fr_box_int16(*src_port) : fr_box_strvalue("*"),
-                                       interface ? interface : "*",
-                                       fr_syserror(errno));
-               return ret;
-       }
-
-       if (!src_port) goto done;
-
-       /*
-        *      FreeBSD jail issues.  We bind to 0.0.0.0, but the
-        *      kernel instead binds us to a 1.2.3.4.  So once the
-        *      socket is bound, ask it what it's IP address is.
-        *
-        *      @todo - Uh... we don't update src_ipaddr with the new
-        *      IP address.  This means that we don't tell the caller
-        *      what IP address we're bound to.  That seems wrong.
-        */
-       salen = sizeof(salocal);
-       memset(&salocal, 0, salen);
-       if (getsockname(sockfd, (struct sockaddr *) &salocal, &salen) < 0) {
-               fr_strerror_printf_push("Failed getting socket name: %s", fr_syserror(errno));
-               return -1;
-       }
-
-       if (fr_ipaddr_from_sockaddr(&my_ipaddr, &my_port, &salocal, salen) < 0) return -1;
-       *src_port = my_port;
-
-done:
-#ifdef HAVE_CAPABILITY_H
-       /*
-        *      Clear any errors we may have produced in the
-        *      capabilities check.
-        */
-       fr_strerror_clear();
-#endif
-       return 0;
-}
index 2a59f451a2056f7c145e39a6333d0342c39f71e7..d05c9f195018c67e2efe8742dfd75e11c34a6874 100644 (file)
@@ -302,7 +302,7 @@ int         fr_socket_client_unix(char const *path, 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(char const *ifname, fr_ipaddr_t const *src_ipaddr,
+int            fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *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);
 
@@ -310,7 +310,7 @@ int         fr_socket_server_udp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const
 
 int            fr_socket_server_tcp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
 
-int            fr_socket_bind(int sockfd, fr_ipaddr_t const *ipaddr, uint16_t *port, char const *interface);
+int            fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port);
 
 #ifdef __cplusplus
 }
index 93a2861c7f723f303d6392d35d3a76640030bf08..7ab8736076ef885b7fd79284ccf7ab03aff95fc5 100644 (file)
@@ -95,9 +95,10 @@ static int _udp_queue_entry_free(fr_udp_queue_entry_t *entry)
 fr_udp_queue_t *fr_udp_queue_alloc(TALLOC_CTX *ctx, fr_udp_queue_config_t const *config, fr_event_list_t *el,
                                   fr_udp_queue_resume_t resume)
 {
-       fr_udp_queue_t *uq;
-       int fd;
-       uint16_t port = config->port;
+       fr_udp_queue_t  *uq;
+       int             fd;
+       fr_ipaddr_t     ipaddr = config->ipaddr;
+       uint16_t        port = config->port;
 
        /*
         *      Open the socket.
@@ -123,7 +124,7 @@ fr_udp_queue_t *fr_udp_queue_alloc(TALLOC_CTX *ctx, fr_udp_queue_config_t const
         *      Bind to the given interface.
         */
        if (config->interface &&
-           (fr_socket_bind(fd, &config->ipaddr, &port, config->interface) < 0)) goto error;
+           (fr_socket_bind(fd, config->interface, &ipaddr, &port) < 0)) goto error;
 
 #ifdef SO_SNDBUF
        /*
index 5b182fcae26950cbba0a721ba4a72045a8df685a..2022335201baeacd61d01049217f21f92684f134 100644 (file)
@@ -248,6 +248,7 @@ static int mod_open(fr_listen_t *li)
        proto_bfd_udp_thread_t  *thread = talloc_get_type_abort(li->thread_instance, proto_bfd_udp_thread_t);
 
        int                             sockfd;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        li->fd = sockfd = fr_socket_server_udp(&inst->ipaddr, &port, inst->port_name, true);
@@ -308,7 +309,7 @@ static int mod_open(fr_listen_t *li)
        /*
         *      @todo - cache ifindex for use with udpfromto.
         */
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+       if (fr_socket_bind(sockfd, inst->interface, &ipaddr, &port) < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
                goto error;
index 4ec35d45247fc12e43549f026df62f1fda2ed58e..0b5b8b6bc244fad239238a730d049ed0fdc7c642 100644 (file)
@@ -502,6 +502,7 @@ static int mod_open(fr_listen_t *li)
        proto_dhcpv4_udp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_dhcpv4_udp_thread_t);
 
        int                             sockfd, rcode;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        li->fd = sockfd = fr_socket_server_udp(&inst->ipaddr, &port, inst->port_name, true);
@@ -548,7 +549,7 @@ static int mod_open(fr_listen_t *li)
                }
        }
 
-       rcode = fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface);
+       rcode = fr_socket_bind(sockfd, inst->interface, &ipaddr, &port);
        if (rcode < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
index 45ac1bf31fecc778503cc0127ba7d6c0e1f687db..8889561b579be43623c3a5d18fc8e9039678f4a6 100644 (file)
@@ -283,6 +283,7 @@ static int mod_open(fr_listen_t *li)
        proto_dhcpv6_udp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_dhcpv6_udp_thread_t);
 
        int                             sockfd, rcode;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        li->fd = sockfd = fr_socket_server_udp(&inst->ipaddr, &port, inst->port_name, true);
@@ -323,7 +324,7 @@ static int mod_open(fr_listen_t *li)
         *      SUID up is really only needed if interface is set, OR port <1024.
         */
        rad_suid_up();
-       rcode = fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface);
+       rcode = fr_socket_bind(sockfd, inst->interface, &ipaddr, &port);
        rad_suid_down();
        if (rcode < 0) {
                PERROR("Failed binding socket");
index 2f0bc52eeab05377dd32295bce6d2e43bb9f75b6..527abb50bf8e98e4a6740ff248da970afd76696c 100644 (file)
@@ -258,6 +258,7 @@ static int mod_open(fr_listen_t *li)
        proto_dns_udp_thread_t  *thread = talloc_get_type_abort(li->thread_instance, proto_dns_udp_thread_t);
 
        int                             sockfd, rcode;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        li->fd = sockfd = fr_socket_server_udp(&inst->ipaddr, &port, "domain", true);
@@ -287,7 +288,7 @@ static int mod_open(fr_listen_t *li)
         *      SUID up is really only needed if interface is set, OR port <1024.
         */
        rad_suid_up();
-       rcode = fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface);
+       rcode = fr_socket_bind(sockfd, inst->interface, &ipaddr, &port);
        rad_suid_down();
        if (rcode < 0) {
                PERROR("Failed binding socket");
index 632140e296413bc7954ce94c760446b49854b505..8da17bde0d17d4313b90fa43689a128a8134eb28 100644 (file)
@@ -303,7 +303,7 @@ static int mod_open(fr_listen_t *li)
 
        (void) fr_nonblock(sockfd);
 
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+       if (fr_socket_bind(sockfd, inst->interface, &inst->ipaddr, &port) < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
                goto error;
index 4230d8ab0e0a142b0a8f4fbfb70de34dc59866c6..60037c9dffe93430b08da49d2d8af644f17b7c5b 100644 (file)
@@ -290,6 +290,7 @@ static int mod_open(fr_listen_t *li)
        proto_radius_tcp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_radius_tcp_thread_t);
 
        int                             sockfd;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        fr_assert(!thread->connection);
@@ -303,7 +304,7 @@ static int mod_open(fr_listen_t *li)
 
        (void) fr_nonblock(sockfd);
 
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+       if (fr_socket_bind(sockfd, inst->interface, &ipaddr, &port) < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
                goto error;
index 5fc26207132c1d796b94a84b988d94627db08cf6..803678a8c31119b682ca839522efc97ceb658bb3 100644 (file)
@@ -293,6 +293,7 @@ static int mod_open(fr_listen_t *li)
        proto_radius_udp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_radius_udp_thread_t);
 
        int                             sockfd;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        li->fd = sockfd = fr_socket_server_udp(&inst->ipaddr, &port, inst->port_name, true);
@@ -339,7 +340,7 @@ static int mod_open(fr_listen_t *li)
        }
 #endif
 
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+       if (fr_socket_bind(sockfd, inst->interface, &ipaddr, &port) < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
                goto error;
index 0f6ec7ab71693edd55df27b502b531c31ff67dd8..5b9da28b28992e194d02bcf86d6e7bd0859d28c8 100644 (file)
@@ -302,6 +302,7 @@ static int mod_open(fr_listen_t *li)
        proto_tacacs_tcp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_tacacs_tcp_thread_t);
 
        int                             sockfd;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        fr_assert(!thread->connection);
@@ -315,7 +316,7 @@ static int mod_open(fr_listen_t *li)
 
        (void) fr_nonblock(sockfd);
 
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+       if (fr_socket_bind(sockfd, inst->interface, &ipaddr, &port) < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
                goto error;
index d550080147dc7eb7c2f15741327afbf2f07f48ad..60bce56cf504acf821eff19b3ade62d8ad49e67f 100644 (file)
@@ -285,6 +285,7 @@ static int mod_open(fr_listen_t *li)
        proto_vmps_udp_thread_t         *thread = talloc_get_type_abort(li->thread_instance, proto_vmps_udp_thread_t);
 
        int                             sockfd;
+       fr_ipaddr_t                     ipaddr = inst->ipaddr;
        uint16_t                        port = inst->port;
 
        li->fd = sockfd = fr_socket_server_udp(&inst->ipaddr, &port, inst->port_name, true);
@@ -309,7 +310,7 @@ static int mod_open(fr_listen_t *li)
                }
        }
 
-       if (fr_socket_bind(sockfd, &inst->ipaddr, &port, inst->interface) < 0) {
+       if (fr_socket_bind(sockfd, inst->interface, &ipaddr, &port) < 0) {
                close(sockfd);
                PERROR("Failed binding socket");
                goto error;
index 568ced497226901ee38dbada378409024135b538..04423cd6e0e8115ec43fbfb5c8d9f7961b797607 100644 (file)
@@ -468,7 +468,7 @@ static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
        /*
         *      Only bind if we have a src and interface.
         */
-       if (src && inst->interface && (fr_socket_bind(fd, src, NULL, inst->interface) < 0)) {
+       if (src && inst->interface && (fr_socket_bind(fd, inst->interface, src, NULL) < 0)) {
                close(fd);
                return -1;
        }
index a65a981df4eb0ed6366b488fb15d2e2fb4e80823..8c7c6901ec99e94de442ee8a2eac115a041a5030 100644 (file)
@@ -247,7 +247,7 @@ static void master_process(TALLOC_CTX *ctx)
                fr_exit_now(EXIT_FAILURE);
        }
 
-       if (fr_socket_bind(sockfd, &my_ipaddr, &my_port, NULL) < 0) {
+       if (fr_socket_bind(sockfd, NULL, &my_ipaddr, &my_port) < 0) {
                fr_perror("radius_test: Failed binding to socket");
                fr_exit_now(EXIT_FAILURE);
        }
index 64e3b357bc52bf723f99d8e399e15c811cd4f0f8..de0c92bfd6ce94026406aa0f5c49729a6816d5d8 100644 (file)
@@ -119,7 +119,7 @@ static int test_open(void *ctx, UNUSED void const *master_ctx)
                fr_exit_now(EXIT_FAILURE);
        }
 
-       if (fr_socket_bind(io_ctx->sockfd, &io_ctx->ipaddr, &io_ctx->port, NULL) < 0) {
+       if (fr_socket_bind(io_ctx->sockfd, NULL, &io_ctx->ipaddr, &io_ctx->port) < 0) {
                fr_perror("radius_test: Failed binding to socket");
                fr_exit_now(EXIT_FAILURE);
        }