Last active
February 12, 2017 19:48
-
-
Save alfredh/e039f5cbd8eb43e99c7d8cb5631c2a40 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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