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) {
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;
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) {
#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
}
#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
*
* 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);
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;
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.
*/
*
* 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);
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.
* - 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;
}
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.
*/
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);
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));
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;
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;
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;
/*
* 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:
/*
* 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);