Skip to content

Instantly share code, notes, and snippets.

@alfredh
Last active February 12, 2017 19:48
Show Gist options
  • Save alfredh/e039f5cbd8eb43e99c7d8cb5631c2a40 to your computer and use it in GitHub Desktop.
Save alfredh/e039f5cbd8eb43e99c7d8cb5631c2a40 to your computer and use it in GitHub Desktop.
#include <re.h>
/*
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 const struct policy {
const char *addr;
unsigned prefix_len;
unsigned precedence;
} policy_table[] = {
{ "::1", 128, 50 },
{ "::", 0, 40 },
{ "::ffff:0:0", 96, 35 },
{ "2002::", 16, 30 },
{ "2001::", 32, 5 },
{ "fc00::", 7, 3 },
{ "::", 96, 1 },
{ "fec0::", 10, 1 },
{ "3ffe::", 16, 1 },
};
static void sa_init_netmask(struct sa *netmask, unsigned prefix_len)
{
long i, j;
if (!netmask)
return;
sa_init(netmask, AF_INET6);
for (i = prefix_len, j = 0; i > 0; i -= 8, ++j) {
uint8_t b;
b = i >= 8 ? 0xff : (unsigned)((0xffu << ( 8 - i ) ) & 0xffu);
netmask->u.in6.sin6_addr.s6_addr[j] = b;
}
}
static void sa_apply_mask(struct sa *dst, const struct sa *src,
const struct sa *netmask)
{
unsigned i;
if (!dst || !src || !netmask)
return;
*dst = *src;
for (i = 0; i < 16; i++) {
dst->u.in6.sin6_addr.s6_addr[i] =
src->u.in6.sin6_addr.s6_addr[i] &
netmask->u.in6.sin6_addr.s6_addr[i];
}
}
/*
* The policy table is a longest-matching-prefix lookup table
*/
static int ipv6_calc_precedence(const struct sa *sa)
{
const struct policy *policy_best = NULL;
unsigned prefix_longest = 0;
unsigned i;
if (AF_INET6 != sa_af(sa)) {
re_printf("not an ipv6 address\n");
return 0;
}
for (i=0; i<ARRAY_SIZE(policy_table); i++) {
const struct policy *policy = &policy_table[i];
struct sa netmask;
struct sa addr;
struct sa addr_input;
bool match;
sa_set_str(&addr, policy->addr, 0);
sa_init_netmask(&netmask, policy->prefix_len);
sa_apply_mask(&addr, &addr, &netmask);
sa_apply_mask(&addr_input, sa, &netmask);
match = sa_cmp(&addr, &addr_input, SA_ADDR);
if (match && policy->prefix_len >= prefix_longest) {
policy_best = policy;
prefix_longest = policy->prefix_len;
}
}
if (policy_best) {
return policy_best->precedence;
}
else {
re_printf("no matches in policy table\n");
return 0;
}
return 0;
}
static bool net_ifaddr_handler(const char *ifname, const struct sa *sa,
void *arg)
{
unsigned precedence;
(void)arg;
if (AF_INET6 != sa_af(sa))
return false;
precedence = ipv6_calc_precedence(sa);
re_printf("ifaddr: %10s %32j precedence=%u\n",
ifname, sa, precedence);
return false;
}
int main(void)
{
re_printf("List of IPv6 addresses:\n");
net_getifaddrs(net_ifaddr_handler, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment