kernel-netlink: Prefer matching label when selecting IPv6 source addresses
This implements rule 6 of RFC 6724 using the default priority table, so that e.g. global addresses are preferred over ULAs (which also have global scope) when the destination is a global address. Fixes #2138.
This commit is contained in:
parent
965daa1df3
commit
7a40162cb7
|
@ -794,6 +794,68 @@ static u_char get_scope(host_t *ip)
|
|||
return 14;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the label of the given unicast IP address.
|
||||
*
|
||||
* We currently only support the default table given in RFC 6724:
|
||||
*
|
||||
* Prefix Precedence Label
|
||||
* ::1/128 50 0
|
||||
* ::/0 40 1
|
||||
* ::ffff:0:0/96 35 4
|
||||
* 2002::/16 30 2
|
||||
* 2001::/32 5 5
|
||||
* fc00::/7 3 13
|
||||
* ::/96 1 3
|
||||
* fec0::/10 1 11
|
||||
* 3ffe::/16 1 12
|
||||
*/
|
||||
static u_char get_label(host_t *ip)
|
||||
{
|
||||
struct {
|
||||
chunk_t net;
|
||||
u_char prefix;
|
||||
u_char label;
|
||||
} priorities[] = {
|
||||
/* priority table ordered by prefix */
|
||||
/* ::1/128 */
|
||||
{ chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01), 128, 0 },
|
||||
/* ::ffff:0:0/96 */
|
||||
{ chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00), 96, 4 },
|
||||
/* ::/96 */
|
||||
{ chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 96, 3 },
|
||||
/* 2001::/32 */
|
||||
{ chunk_from_chars(0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 32, 5 },
|
||||
/* 2002::/16 */
|
||||
{ chunk_from_chars(0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 16, 2 },
|
||||
/* 3ffe::/16 */
|
||||
{ chunk_from_chars(0x3f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 16, 12 },
|
||||
/* fec0::/10 */
|
||||
{ chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 10, 11 },
|
||||
/* fc00::/7 */
|
||||
{ chunk_from_chars(0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 7, 13 },
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < countof(priorities); i++)
|
||||
{
|
||||
if (host_in_subnet(ip, priorities[i].net, priorities[i].prefix))
|
||||
{
|
||||
return priorities[i].label;
|
||||
}
|
||||
}
|
||||
/* ::/0 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the common prefix in bits up to the length of a's
|
||||
* prefix, defined by RFC 6724 as the portion of the address not including the
|
||||
|
@ -829,7 +891,7 @@ static u_char common_prefix(host_t *a, host_t *b)
|
|||
static bool is_address_better(private_kernel_netlink_net_t *this,
|
||||
addr_entry_t *a, addr_entry_t *b, host_t *d)
|
||||
{
|
||||
u_char sa, sb, sd, pa, pb;
|
||||
u_char sa, sb, sd, la, lb, ld, pa, pb;
|
||||
|
||||
/* rule 2: prefer appropriate scope */
|
||||
if (d)
|
||||
|
@ -858,9 +920,22 @@ static bool is_address_better(private_kernel_netlink_net_t *this,
|
|||
/* rule 4 is not applicable as we don't know if an address is a home or
|
||||
* care-of addresses.
|
||||
* rule 5 does not apply as we only compare addresses from one interface
|
||||
* rule 6 requires a policy table (optionally configurable) to match
|
||||
* configurable labels
|
||||
*/
|
||||
/* rule 6: prefer matching label */
|
||||
if (d)
|
||||
{
|
||||
la = get_label(a->ip);
|
||||
lb = get_label(b->ip);
|
||||
ld = get_label(d);
|
||||
if (la == ld && lb != ld)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (lb == ld && la != ld)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
/* rule 7: prefer temporary addresses (WE REVERSE THIS BY DEFAULT!) */
|
||||
if ((a->flags & IFA_F_TEMPORARY) != (b->flags & IFA_F_TEMPORARY))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue