1 /* $OpenBSD: util.c,v 1.9 2016/09/02 16:36:33 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org> 6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 24 #include <string.h> 25 26 #include "eigrpd.h" 27 #include "log.h" 28 29 uint8_t 30 mask2prefixlen(in_addr_t ina) 31 { 32 if (ina == 0) 33 return (0); 34 else 35 return (33 - ffs(ntohl(ina))); 36 } 37 38 uint8_t 39 mask2prefixlen6(struct sockaddr_in6 *sa_in6) 40 { 41 uint8_t l = 0, *ap, *ep; 42 43 /* 44 * sin6_len is the size of the sockaddr so substract the offset of 45 * the possibly truncated sin6_addr struct. 46 */ 47 ap = (uint8_t *)&sa_in6->sin6_addr; 48 ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; 49 for (; ap < ep; ap++) { 50 /* this "beauty" is adopted from sbin/route/show.c ... */ 51 switch (*ap) { 52 case 0xff: 53 l += 8; 54 break; 55 case 0xfe: 56 l += 7; 57 return (l); 58 case 0xfc: 59 l += 6; 60 return (l); 61 case 0xf8: 62 l += 5; 63 return (l); 64 case 0xf0: 65 l += 4; 66 return (l); 67 case 0xe0: 68 l += 3; 69 return (l); 70 case 0xc0: 71 l += 2; 72 return (l); 73 case 0x80: 74 l += 1; 75 return (l); 76 case 0x00: 77 return (l); 78 default: 79 fatalx("non contiguous inet6 netmask"); 80 } 81 } 82 83 return (l); 84 } 85 86 in_addr_t 87 prefixlen2mask(uint8_t prefixlen) 88 { 89 if (prefixlen == 0) 90 return (0); 91 92 return (htonl(0xffffffff << (32 - prefixlen))); 93 } 94 95 struct in6_addr * 96 prefixlen2mask6(uint8_t prefixlen) 97 { 98 static struct in6_addr mask; 99 int i; 100 101 memset(&mask, 0, sizeof(mask)); 102 for (i = 0; i < prefixlen / 8; i++) 103 mask.s6_addr[i] = 0xff; 104 i = prefixlen % 8; 105 if (i) 106 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 107 108 return (&mask); 109 } 110 111 void 112 eigrp_applymask(int af, union eigrpd_addr *dest, const union eigrpd_addr *src, 113 int prefixlen) 114 { 115 struct in6_addr mask; 116 int i; 117 118 switch (af) { 119 case AF_INET: 120 dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen); 121 break; 122 case AF_INET6: 123 memset(&mask, 0, sizeof(mask)); 124 for (i = 0; i < prefixlen / 8; i++) 125 mask.s6_addr[i] = 0xff; 126 i = prefixlen % 8; 127 if (i) 128 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 129 130 for (i = 0; i < 16; i++) 131 dest->v6.s6_addr[i] = src->v6.s6_addr[i] & 132 mask.s6_addr[i]; 133 break; 134 default: 135 fatalx("eigrp_applymask: unknown af"); 136 } 137 } 138 139 int 140 eigrp_addrcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b) 141 { 142 switch (af) { 143 case AF_INET: 144 if (a->v4.s_addr == b->v4.s_addr) 145 return (0); 146 return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1); 147 case AF_INET6: 148 return (!!memcmp(&a->v6, &b->v6, sizeof(struct in6_addr))); 149 default: 150 fatalx("eigrp_addrcmp: unknown af"); 151 } 152 } 153 154 int 155 eigrp_addrisset(int af, const union eigrpd_addr *addr) 156 { 157 switch (af) { 158 case AF_UNSPEC: 159 return (0); 160 case AF_INET: 161 if (addr->v4.s_addr != INADDR_ANY) 162 return (1); 163 break; 164 case AF_INET6: 165 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6)) 166 return (1); 167 break; 168 default: 169 fatalx("eigrp_addrisset: unknown af"); 170 } 171 172 return (0); 173 } 174 175 int 176 eigrp_prefixcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b, 177 uint8_t prefixlen) 178 { 179 in_addr_t mask, aa, ba; 180 int i; 181 uint8_t m; 182 183 switch (af) { 184 case AF_INET: 185 if (prefixlen == 0) 186 return (0); 187 if (prefixlen > 32) 188 fatalx("eigrp_prefixcmp: bad IPv4 prefixlen"); 189 mask = htonl(prefixlen2mask(prefixlen)); 190 aa = htonl(a->v4.s_addr) & mask; 191 ba = htonl(b->v4.s_addr) & mask; 192 return (aa - ba); 193 case AF_INET6: 194 if (prefixlen == 0) 195 return (0); 196 if (prefixlen > 128) 197 fatalx("eigrp_prefixcmp: bad IPv6 prefixlen"); 198 for (i = 0; i < prefixlen / 8; i++) 199 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 200 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 201 i = prefixlen % 8; 202 if (i) { 203 m = 0xff00 >> i; 204 if ((a->v6.s6_addr[prefixlen / 8] & m) != 205 (b->v6.s6_addr[prefixlen / 8] & m)) 206 return ((a->v6.s6_addr[prefixlen / 8] & m) - 207 (b->v6.s6_addr[prefixlen / 8] & m)); 208 } 209 return (0); 210 default: 211 fatalx("eigrp_prefixcmp: unknown af"); 212 } 213 return (-1); 214 } 215 216 int 217 bad_addr_v4(struct in_addr addr) 218 { 219 uint32_t a = ntohl(addr.s_addr); 220 221 if (((a >> IN_CLASSA_NSHIFT) == 0) || 222 ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) || 223 IN_MULTICAST(a) || IN_BADCLASS(a)) 224 return (1); 225 226 return (0); 227 } 228 229 int 230 bad_addr_v6(struct in6_addr *addr) 231 { 232 if (IN6_IS_ADDR_UNSPECIFIED(addr) || 233 IN6_IS_ADDR_LOOPBACK(addr) || 234 IN6_IS_ADDR_MULTICAST(addr) || 235 IN6_IS_ADDR_SITELOCAL(addr) || 236 IN6_IS_ADDR_V4MAPPED(addr) || 237 IN6_IS_ADDR_V4COMPAT(addr)) 238 return (1); 239 240 return (0); 241 } 242 243 int 244 bad_addr(int af, union eigrpd_addr *addr) 245 { 246 switch (af) { 247 case AF_INET: 248 return (bad_addr_v4(addr->v4)); 249 case AF_INET6: 250 return (bad_addr_v6(&addr->v6)); 251 default: 252 fatalx("bad_addr: unknown af"); 253 } 254 } 255 256 void 257 embedscope(struct sockaddr_in6 *sin6) 258 { 259 uint16_t tmp16; 260 261 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 262 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 263 if (tmp16 != 0) { 264 log_warnx("%s: address %s already has embeded scope %u", 265 __func__, log_sockaddr(sin6), ntohs(tmp16)); 266 } 267 tmp16 = htons(sin6->sin6_scope_id); 268 memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 269 sin6->sin6_scope_id = 0; 270 } 271 } 272 273 void 274 recoverscope(struct sockaddr_in6 *sin6) 275 { 276 uint16_t tmp16; 277 278 if (sin6->sin6_scope_id != 0) 279 log_warnx("%s: address %s already has scope id %u", 280 __func__, log_sockaddr(sin6), sin6->sin6_scope_id); 281 282 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 283 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 284 sin6->sin6_scope_id = ntohs(tmp16); 285 sin6->sin6_addr.s6_addr[2] = 0; 286 sin6->sin6_addr.s6_addr[3] = 0; 287 } 288 } 289 290 void 291 addscope(struct sockaddr_in6 *sin6, uint32_t id) 292 { 293 if (sin6->sin6_scope_id != 0) 294 log_warnx("%s: address %s already has scope id %u", __func__, 295 log_sockaddr(sin6), sin6->sin6_scope_id); 296 297 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) 298 sin6->sin6_scope_id = id; 299 } 300 301 void 302 clearscope(struct in6_addr *in6) 303 { 304 if (IN6_IS_SCOPE_EMBED(in6)) { 305 in6->s6_addr[2] = 0; 306 in6->s6_addr[3] = 0; 307 } 308 } 309 310 void 311 sa2addr(struct sockaddr *sa, int *af, union eigrpd_addr *addr) 312 { 313 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 314 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 315 316 memset(addr, 0, sizeof(*addr)); 317 switch (sa->sa_family) { 318 case AF_INET: 319 *af = AF_INET; 320 addr->v4 = sa_in->sin_addr; 321 break; 322 case AF_INET6: 323 *af = AF_INET6; 324 addr->v6 = sa_in6->sin6_addr; 325 break; 326 default: 327 fatalx("sa2addr: unknown af"); 328 } 329 } 330