1*ef8d499eSDavid van Moolenbroek /* LWIP service - addrpol.c - address policy table and values */
2*ef8d499eSDavid van Moolenbroek /*
3*ef8d499eSDavid van Moolenbroek * The main purpose of this module is to implement the address policy table
4*ef8d499eSDavid van Moolenbroek * described in RFC 6724. In general, the policy table is used for two
5*ef8d499eSDavid van Moolenbroek * purposes: source address selection, which is part of this service, and
6*ef8d499eSDavid van Moolenbroek * destination address selection, which is implemented in libc. NetBSD 7, the
7*ef8d499eSDavid van Moolenbroek * version that MINIX 3 is synced against at this moment, does not actually
8*ef8d499eSDavid van Moolenbroek * implement the libc part yet, though. That will change with NetBSD 8, where
9*ef8d499eSDavid van Moolenbroek * libc uses sysctl(7) to obtain the kernel's policy table, which itself can be
10*ef8d499eSDavid van Moolenbroek * changed with the new ip6addrctl(8) utility. Once we resync to NetBSD 8, we
11*ef8d499eSDavid van Moolenbroek * will also have to support this new functionality, and this module is where
12*ef8d499eSDavid van Moolenbroek * it would be implemented. Since NetBSD 7 is even lacking the necessary
13*ef8d499eSDavid van Moolenbroek * definitions, we cannot do that ahead of time, though. Thus, until then,
14*ef8d499eSDavid van Moolenbroek * this module is rather simple, as it only implements a static policy table
15*ef8d499eSDavid van Moolenbroek * used for source address selection. No changes beyond this module should be
16*ef8d499eSDavid van Moolenbroek * necessary, e.g. we are purposely not caching labels for local addresses.
17*ef8d499eSDavid van Moolenbroek */
18*ef8d499eSDavid van Moolenbroek
19*ef8d499eSDavid van Moolenbroek #include "lwip.h"
20*ef8d499eSDavid van Moolenbroek
21*ef8d499eSDavid van Moolenbroek /*
22*ef8d499eSDavid van Moolenbroek * Address policy table. Currently hardcoded to the default of RFC 6724.
23*ef8d499eSDavid van Moolenbroek * Sorted by prefix length, so that the first match is always also the longest.
24*ef8d499eSDavid van Moolenbroek */
25*ef8d499eSDavid van Moolenbroek static const struct {
26*ef8d499eSDavid van Moolenbroek ip_addr_t ipaddr;
27*ef8d499eSDavid van Moolenbroek unsigned int prefix;
28*ef8d499eSDavid van Moolenbroek int precedence;
29*ef8d499eSDavid van Moolenbroek int label;
30*ef8d499eSDavid van Moolenbroek } addrpol_table[] = {
31*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0, 0, 0, 1), 128, 50, 0 },
32*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0, 0, 0x0000ffffUL, 0), 96, 35, 4 },
33*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0, 0, 0, 0), 96, 1, 3 },
34*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0x20010000UL, 0, 0, 0), 32, 5, 5 },
35*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0x20020000UL, 0, 0, 0), 16, 30, 2 },
36*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0x3ffe0000UL, 0, 0, 0), 16, 1, 12 },
37*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0xfec00000UL, 0, 0, 0), 10, 1, 11 },
38*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0xfc000000UL, 0, 0, 0), 7, 3, 13 },
39*ef8d499eSDavid van Moolenbroek { IPADDR6_INIT_HOST(0, 0, 0, 0), 0, 40, 1 }
40*ef8d499eSDavid van Moolenbroek };
41*ef8d499eSDavid van Moolenbroek
42*ef8d499eSDavid van Moolenbroek /*
43*ef8d499eSDavid van Moolenbroek * Obtain the label value for the given IP address from the address policy
44*ef8d499eSDavid van Moolenbroek * table. Currently only IPv6 addresses may be given. This function is linear
45*ef8d499eSDavid van Moolenbroek * in number of address policy table entries, requiring a relatively expensive
46*ef8d499eSDavid van Moolenbroek * normalization operation for each entry, so it should not be called lightly.
47*ef8d499eSDavid van Moolenbroek * Its results should not be cached beyond local contexts either, because the
48*ef8d499eSDavid van Moolenbroek * policy table itself may be changed from userland (in the future).
49*ef8d499eSDavid van Moolenbroek *
50*ef8d499eSDavid van Moolenbroek * TODO: convert IPv4 addresses to IPv4-mapped IPv6 addresses.
51*ef8d499eSDavid van Moolenbroek * TODO: embed the interface index in link-local addresses.
52*ef8d499eSDavid van Moolenbroek */
53*ef8d499eSDavid van Moolenbroek int
addrpol_get_label(const ip_addr_t * iporig)54*ef8d499eSDavid van Moolenbroek addrpol_get_label(const ip_addr_t * iporig)
55*ef8d499eSDavid van Moolenbroek {
56*ef8d499eSDavid van Moolenbroek ip_addr_t ipaddr;
57*ef8d499eSDavid van Moolenbroek unsigned int i;
58*ef8d499eSDavid van Moolenbroek
59*ef8d499eSDavid van Moolenbroek assert(IP_IS_V6(iporig));
60*ef8d499eSDavid van Moolenbroek
61*ef8d499eSDavid van Moolenbroek /*
62*ef8d499eSDavid van Moolenbroek * The policy table is sorted by prefix length such that the first
63*ef8d499eSDavid van Moolenbroek * match is also the one with the longest prefix, and as such the best.
64*ef8d499eSDavid van Moolenbroek */
65*ef8d499eSDavid van Moolenbroek for (i = 0; i < __arraycount(addrpol_table); i++) {
66*ef8d499eSDavid van Moolenbroek addr_normalize(&ipaddr, iporig, addrpol_table[i].prefix);
67*ef8d499eSDavid van Moolenbroek
68*ef8d499eSDavid van Moolenbroek if (ip_addr_cmp(&addrpol_table[i].ipaddr, &ipaddr))
69*ef8d499eSDavid van Moolenbroek return addrpol_table[i].label;
70*ef8d499eSDavid van Moolenbroek }
71*ef8d499eSDavid van Moolenbroek
72*ef8d499eSDavid van Moolenbroek /*
73*ef8d499eSDavid van Moolenbroek * We cannot possibly get here with the default policy table, because
74*ef8d499eSDavid van Moolenbroek * the last entry will always match. It is not clear what we should
75*ef8d499eSDavid van Moolenbroek * return if there is no matching entry, though. For now, we return
76*ef8d499eSDavid van Moolenbroek * the default label value for the default (::/0) entry, which is 1.
77*ef8d499eSDavid van Moolenbroek */
78*ef8d499eSDavid van Moolenbroek return 1;
79*ef8d499eSDavid van Moolenbroek }
80*ef8d499eSDavid van Moolenbroek
81*ef8d499eSDavid van Moolenbroek /*
82*ef8d499eSDavid van Moolenbroek * Return an opaque positive value (possibly zero) that represents the scope of
83*ef8d499eSDavid van Moolenbroek * the given IP address. A larger value indicates a wider scope. The 'is_src'
84*ef8d499eSDavid van Moolenbroek * flag indicates whether the address is a source or a destination address,
85*ef8d499eSDavid van Moolenbroek * which affects the value returned for unknown addresses. A scope is a direct
86*ef8d499eSDavid van Moolenbroek * function of only the given address, so the result may be cached on a per-
87*ef8d499eSDavid van Moolenbroek * address basis without risking invalidation at any point in time.
88*ef8d499eSDavid van Moolenbroek */
89*ef8d499eSDavid van Moolenbroek int
addrpol_get_scope(const ip_addr_t * ipaddr,int is_src)90*ef8d499eSDavid van Moolenbroek addrpol_get_scope(const ip_addr_t * ipaddr, int is_src)
91*ef8d499eSDavid van Moolenbroek {
92*ef8d499eSDavid van Moolenbroek const ip6_addr_t *ip6addr;
93*ef8d499eSDavid van Moolenbroek
94*ef8d499eSDavid van Moolenbroek /*
95*ef8d499eSDavid van Moolenbroek * For now, all IPv4 addresses are considered global. This function is
96*ef8d499eSDavid van Moolenbroek * currently called only for IPv6 addresses anyway.
97*ef8d499eSDavid van Moolenbroek */
98*ef8d499eSDavid van Moolenbroek if (IP_IS_V4(ipaddr))
99*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_GLOBAL;
100*ef8d499eSDavid van Moolenbroek
101*ef8d499eSDavid van Moolenbroek assert(IP_IS_V6(ipaddr));
102*ef8d499eSDavid van Moolenbroek
103*ef8d499eSDavid van Moolenbroek ip6addr = ip_2_ip6(ipaddr);
104*ef8d499eSDavid van Moolenbroek
105*ef8d499eSDavid van Moolenbroek /*
106*ef8d499eSDavid van Moolenbroek * These are ordered not by ascending scope, but (roughly) by expected
107*ef8d499eSDavid van Moolenbroek * likeliness to match, for performance reasons.
108*ef8d499eSDavid van Moolenbroek */
109*ef8d499eSDavid van Moolenbroek if (ip6_addr_isglobal(ip6addr))
110*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_GLOBAL;
111*ef8d499eSDavid van Moolenbroek
112*ef8d499eSDavid van Moolenbroek if (ip6_addr_islinklocal(ip6addr) || ip6_addr_isloopback(ip6addr))
113*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_LINK_LOCAL;
114*ef8d499eSDavid van Moolenbroek
115*ef8d499eSDavid van Moolenbroek /*
116*ef8d499eSDavid van Moolenbroek * We deliberately deviate from RFC 6724 Sec. 3.1 by considering
117*ef8d499eSDavid van Moolenbroek * Unique-Local Addresses (ULAs) to be of smaller scope than global
118*ef8d499eSDavid van Moolenbroek * addresses, to avoid that during source address selection, a
119*ef8d499eSDavid van Moolenbroek * preferred ULA is picked over a deprecated global address when given
120*ef8d499eSDavid van Moolenbroek * a global address as destination, as that would likely result in
121*ef8d499eSDavid van Moolenbroek * broken two-way communication.
122*ef8d499eSDavid van Moolenbroek */
123*ef8d499eSDavid van Moolenbroek if (ip6_addr_isuniquelocal(ip6addr))
124*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL;
125*ef8d499eSDavid van Moolenbroek
126*ef8d499eSDavid van Moolenbroek if (ip6_addr_ismulticast(ip6addr))
127*ef8d499eSDavid van Moolenbroek return ip6_addr_multicast_scope(ip6addr);
128*ef8d499eSDavid van Moolenbroek
129*ef8d499eSDavid van Moolenbroek /* Site-local addresses are deprecated. */
130*ef8d499eSDavid van Moolenbroek if (ip6_addr_issitelocal(ip6addr))
131*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_SITE_LOCAL;
132*ef8d499eSDavid van Moolenbroek
133*ef8d499eSDavid van Moolenbroek /*
134*ef8d499eSDavid van Moolenbroek * If the address is a source address, give it a scope beyond global to
135*ef8d499eSDavid van Moolenbroek * make sure that a "real" global address is picked first. If the
136*ef8d499eSDavid van Moolenbroek * address is a destination address, give it a global scope so as to
137*ef8d499eSDavid van Moolenbroek * pick "real" global addresses over unknown-scope source addresses.
138*ef8d499eSDavid van Moolenbroek */
139*ef8d499eSDavid van Moolenbroek if (is_src)
140*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_RESERVEDF; /* greater than GLOBAL */
141*ef8d499eSDavid van Moolenbroek else
142*ef8d499eSDavid van Moolenbroek return IP6_MULTICAST_SCOPE_GLOBAL;
143*ef8d499eSDavid van Moolenbroek }
144