xref: /minix3/minix/net/lwip/addrpol.c (revision ef8d499e2d2af900e9b2ab297171d7b088652482)
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