mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-25 06:03:40 +03:00
Merge pull request #17807 from poettering/bindtodevice
use SO_BINDTOIFINDEX while connect()
This commit is contained in:
commit
34f80876f8
@ -320,7 +320,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) {
|
||||
}
|
||||
|
||||
int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
|
||||
union sockaddr_union *sa = (union sockaddr_union*) _sa;
|
||||
const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
|
||||
|
||||
/* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */
|
||||
|
||||
@ -345,6 +345,25 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
|
||||
}
|
||||
}
|
||||
|
||||
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) {
|
||||
const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
|
||||
|
||||
if (!sa)
|
||||
return NULL;
|
||||
|
||||
switch (sa->sa.sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
return (const union in_addr_union*) &sa->in.sin_addr;
|
||||
|
||||
case AF_INET6:
|
||||
return (const union in_addr_union*) &sa->in6.sin6_addr;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int sockaddr_pretty(
|
||||
const struct sockaddr *_sa,
|
||||
socklen_t salen,
|
||||
|
@ -102,6 +102,7 @@ const char* socket_address_get_path(const SocketAddress *a);
|
||||
bool socket_ipv6_is_supported(void);
|
||||
|
||||
int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
|
||||
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
|
||||
|
||||
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
|
||||
int getpeername_pretty(int fd, bool include_port, char **ret);
|
||||
|
@ -412,9 +412,36 @@ static int dns_scope_socket(
|
||||
if (ret_socket_address)
|
||||
*ret_socket_address = sa;
|
||||
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
|
||||
* 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))) {
|
||||
r = socket_bind_to_ifindex(fd, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
bound = true;
|
||||
}
|
||||
|
||||
r = connect(fd, &sa.sa, salen);
|
||||
if (r < 0 && errno != EINPROGRESS)
|
||||
return -errno;
|
||||
|
||||
if (bound) {
|
||||
r = socket_bind_to_ifindex(fd, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return TAKE_FD(fd);
|
||||
|
@ -58,7 +58,7 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not create runtime directory: %m");
|
||||
|
||||
/* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */
|
||||
/* Drop privileges, but keep three caps. Note that we drop two of those too, later on (see below) */
|
||||
r = drop_privileges(uid, gid,
|
||||
(UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */
|
||||
(UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
|
||||
@ -83,7 +83,7 @@ static int run(int argc, char *argv[]) {
|
||||
(void) manager_check_resolv_conf(m);
|
||||
|
||||
/* Let's drop the remaining caps now */
|
||||
r = capability_bounding_set_drop(0, true);
|
||||
r = capability_bounding_set_drop((UINT64_C(1) << CAP_NET_RAW), true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to drop remaining caps: %m");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user