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