return r;
}
- if (ifindex != 0) {
+ bool addr_is_nonlocal = s->link &&
+ !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) &&
+ in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0;
+
+ if (addr_is_nonlocal && ifindex != 0) {
+ /* As a special exception we don't use UNICAST_IF if we notice that the specified IP address
+ * is on the local host. Otherwise, destination addresses on the local host result in
+ * EHOSTUNREACH, since Linux won't send the packets out of the specified interface, but
+ * delivers them directly to the local socket. */
r = socket_set_unicast_if(fd, sa.sa.sa_family, ifindex);
if (r < 0)
return r;
else {
bool bound = false;
- /* Let's temporarily bind the socket to the specified ifindex. The kernel currently takes
- * only the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions
+ /* Let's temporarily bind the socket to the specified ifindex. Older kernels only take
+ * the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions
* in connect() — and not IP_UNICAST_IF. We don't really want any of the other semantics of
* SO_BINDTODEVICE/SO_BINDTOINDEX, hence we immediately unbind the socket after the fact
* again.
- *
- * As a special exception we don't do this if we notice that the specified IP address is on
- * the local host. SO_BINDTODEVICE in combination with destination addresses on the local
- * host result in EHOSTUNREACH, since Linux won't send the packets out of the specified
- * interface, but delivers them directly to the local socket. */
- if (s->link &&
- !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) &&
- in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0) {
+ */
+ if (addr_is_nonlocal) {
r = socket_bind_to_ifindex(fd, ifindex);
if (r < 0)
return r;