mirror of
https://github.com/systemd/systemd.git
synced 2025-01-10 05:18:17 +03:00
parent
418641f73f
commit
4adf2653e2
@ -81,7 +81,8 @@ static int add_local_address_full(
|
||||
uint32_t priority,
|
||||
uint32_t weight,
|
||||
int family,
|
||||
const union in_addr_union *address) {
|
||||
const union in_addr_union *address,
|
||||
const union in_addr_union *prefsrc) {
|
||||
|
||||
assert(list);
|
||||
assert(n_list);
|
||||
@ -99,6 +100,7 @@ static int add_local_address_full(
|
||||
.weight = weight,
|
||||
.family = family,
|
||||
.address = *address,
|
||||
.prefsrc = prefsrc ? *prefsrc : IN_ADDR_NULL,
|
||||
};
|
||||
|
||||
return 1;
|
||||
@ -112,7 +114,10 @@ int add_local_address(
|
||||
int family,
|
||||
const union in_addr_union *address) {
|
||||
|
||||
return add_local_address_full(list, n_list, ifindex, scope, 0, 0, family, address);
|
||||
return add_local_address_full(
|
||||
list, n_list, ifindex,
|
||||
scope, /* priority = */ 0, /* weight = */ 0,
|
||||
family, address, /* prefsrc = */ NULL);
|
||||
}
|
||||
|
||||
int local_addresses(
|
||||
@ -235,9 +240,14 @@ static int add_local_gateway(
|
||||
uint32_t priority,
|
||||
uint32_t weight,
|
||||
int family,
|
||||
const union in_addr_union *address) {
|
||||
const union in_addr_union *address,
|
||||
const union in_addr_union *prefsrc) {
|
||||
|
||||
return add_local_address_full(list, n_list, ifindex, 0, priority, weight, family, address);
|
||||
return add_local_address_full(
|
||||
list, n_list,
|
||||
ifindex,
|
||||
/* scope = */ 0, priority, weight,
|
||||
family, address, prefsrc);
|
||||
}
|
||||
|
||||
static int parse_nexthop_one(
|
||||
@ -246,6 +256,7 @@ static int parse_nexthop_one(
|
||||
bool allow_via,
|
||||
int family,
|
||||
uint32_t priority,
|
||||
const union in_addr_union *prefsrc,
|
||||
const struct rtnexthop *rtnh) {
|
||||
|
||||
bool has_gw = false;
|
||||
@ -268,7 +279,7 @@ static int parse_nexthop_one(
|
||||
|
||||
union in_addr_union a;
|
||||
memcpy(&a, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(family));
|
||||
r = add_local_gateway(list, n_list, rtnh->rtnh_ifindex, priority, rtnh->rtnh_hops, family, &a);
|
||||
r = add_local_gateway(list, n_list, rtnh->rtnh_ifindex, priority, rtnh->rtnh_hops, family, &a, prefsrc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -294,7 +305,8 @@ static int parse_nexthop_one(
|
||||
return -EBADMSG; /* gateway address should be always IPv6. */
|
||||
|
||||
r = add_local_gateway(list, n_list, rtnh->rtnh_ifindex, priority, rtnh->rtnh_hops, via->family,
|
||||
&(union in_addr_union) { .in6 = via->address.in6 });
|
||||
&(union in_addr_union) { .in6 = via->address.in6 },
|
||||
/* prefsrc = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -311,6 +323,7 @@ static int parse_nexthops(
|
||||
bool allow_via,
|
||||
int family,
|
||||
uint32_t priority,
|
||||
const union in_addr_union *prefsrc,
|
||||
const struct rtnexthop *rtnh,
|
||||
size_t size) {
|
||||
|
||||
@ -334,7 +347,7 @@ static int parse_nexthops(
|
||||
if (ifindex > 0 && rtnh->rtnh_ifindex != ifindex)
|
||||
goto next_nexthop;
|
||||
|
||||
r = parse_nexthop_one(list, n_list, allow_via, family, priority, rtnh);
|
||||
r = parse_nexthop_one(list, n_list, allow_via, family, priority, prefsrc, rtnh);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -393,6 +406,7 @@ int local_gateways(
|
||||
return r;
|
||||
|
||||
for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
|
||||
union in_addr_union prefsrc = IN_ADDR_NULL;
|
||||
uint16_t type;
|
||||
unsigned char dst_len, src_len, table;
|
||||
uint32_t ifi = 0, priority = 0;
|
||||
@ -439,6 +453,10 @@ int local_gateways(
|
||||
if (af != AF_UNSPEC && af != family)
|
||||
continue;
|
||||
|
||||
r = netlink_message_read_in_addr_union(m, RTA_PREFSRC, family, &prefsrc);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
@ -453,7 +471,7 @@ int local_gateways(
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
if (r >= 0) {
|
||||
r = add_local_gateway(&list, &n_list, ifi, priority, 0, family, &gateway);
|
||||
r = add_local_gateway(&list, &n_list, ifi, priority, 0, family, &gateway, &prefsrc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -474,8 +492,10 @@ int local_gateways(
|
||||
if (via.family != AF_INET6)
|
||||
return -EBADMSG;
|
||||
|
||||
/* Ignore prefsrc, and let's take the source address by socket command, if necessary. */
|
||||
r = add_local_gateway(&list, &n_list, ifi, priority, 0, via.family,
|
||||
&(union in_addr_union) { .in6 = via.address.in6 });
|
||||
&(union in_addr_union) { .in6 = via.address.in6 },
|
||||
/* prefsrc = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -490,7 +510,7 @@ int local_gateways(
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
if (r >= 0) {
|
||||
r = parse_nexthops(&list, &n_list, ifindex, allow_via, family, priority, rta_multipath, rta_len);
|
||||
r = parse_nexthops(&list, &n_list, ifindex, allow_via, family, priority, &prefsrc, rta_multipath, rta_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -512,7 +532,51 @@ static int add_local_outbound(
|
||||
int family,
|
||||
const union in_addr_union *address) {
|
||||
|
||||
return add_local_address_full(list, n_list, ifindex, 0, 0, 0, family, address);
|
||||
return add_local_address_full(
|
||||
list, n_list, ifindex,
|
||||
/* scope = */ 0, /* priority = */ 0, /* weight = */ 0,
|
||||
family, address, /* prefsrc = */ NULL);
|
||||
}
|
||||
|
||||
static int add_local_outbound_by_prefsrc(
|
||||
struct local_address **list,
|
||||
size_t *n_list,
|
||||
const struct local_address *gateway,
|
||||
const struct local_address *addresses,
|
||||
size_t n_addresses) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(list);
|
||||
assert(n_list);
|
||||
assert(gateway);
|
||||
|
||||
if (!in_addr_is_set(gateway->family, &gateway->prefsrc))
|
||||
return 0;
|
||||
|
||||
/* If the gateway has prefsrc, then let's honor the field. But, check if the address is assigned to
|
||||
* the same interface, like we do with SO_BINDTOINDEX. */
|
||||
|
||||
bool found = false;
|
||||
FOREACH_ARRAY(a, addresses, n_addresses) {
|
||||
if (a->ifindex != gateway->ifindex)
|
||||
continue;
|
||||
if (a->family != gateway->family)
|
||||
continue;
|
||||
if (in_addr_equal(a->family, &a->address, &gateway->prefsrc) <= 0)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
r = add_local_outbound(list, n_list, gateway->ifindex, gateway->family, &gateway->prefsrc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int local_outbounds(
|
||||
@ -521,9 +585,9 @@ int local_outbounds(
|
||||
int af,
|
||||
struct local_address **ret) {
|
||||
|
||||
_cleanup_free_ struct local_address *list = NULL, *gateways = NULL;
|
||||
_cleanup_free_ struct local_address *list = NULL, *gateways = NULL, *addresses = NULL;
|
||||
size_t n_list = 0;
|
||||
int r, n_gateways;
|
||||
int r, n_gateways, n_addresses;
|
||||
|
||||
/* Determines our default outbound addresses, i.e. the "primary" local addresses we use to talk to IP
|
||||
* addresses behind the default routes. This is still an address of the local host (i.e. this doesn't
|
||||
@ -544,11 +608,21 @@ int local_outbounds(
|
||||
return 0;
|
||||
}
|
||||
|
||||
n_addresses = local_addresses(context, ifindex, af, &addresses);
|
||||
if (n_addresses < 0)
|
||||
return n_addresses;
|
||||
|
||||
FOREACH_ARRAY(i, gateways, n_gateways) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen;
|
||||
|
||||
r = add_local_outbound_by_prefsrc(&list, &n_list, i, addresses, n_addresses);
|
||||
if (r > 0 || r == -EHOSTUNREACH)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = socket(i->family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
@ -12,6 +12,7 @@ struct local_address {
|
||||
uint32_t weight;
|
||||
int family;
|
||||
union in_addr_union address;
|
||||
union in_addr_union prefsrc;
|
||||
};
|
||||
|
||||
bool has_local_address(const struct local_address *addresses, size_t n_addresses, const struct local_address *needle);
|
||||
|
Loading…
Reference in New Issue
Block a user