1 /* $OpenBSD: util.c,v 1.10 2018/12/07 08:40:54 claudio 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 unsigned int l = 0; 42 uint8_t *ap, *ep; 43 44 /* 45 * sin6_len is the size of the sockaddr so substract the offset of 46 * the possibly truncated sin6_addr struct. 47 */ 48 ap = (uint8_t *)&sa_in6->sin6_addr; 49 ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; 50 for (; ap < ep; ap++) { 51 /* this "beauty" is adopted from sbin/route/show.c ... */ 52 switch (*ap) { 53 case 0xff: 54 l += 8; 55 break; 56 case 0xfe: 57 l += 7; 58 goto done; 59 case 0xfc: 60 l += 6; 61 goto done; 62 case 0xf8: 63 l += 5; 64 goto done; 65 case 0xf0: 66 l += 4; 67 goto done; 68 case 0xe0: 69 l += 3; 70 goto done; 71 case 0xc0: 72 l += 2; 73 goto done; 74 case 0x80: 75 l += 1; 76 goto done; 77 case 0x00: 78 goto done; 79 default: 80 fatalx("non contiguous inet6 netmask"); 81 } 82 } 83 84 done: 85 if (l > sizeof(struct in6_addr) * 8) 86 fatalx("inet6 prefixlen out of bound"); 87 return (l); 88 } 89 90 in_addr_t 91 prefixlen2mask(uint8_t prefixlen) 92 { 93 if (prefixlen == 0) 94 return (0); 95 96 return (htonl(0xffffffff << (32 - prefixlen))); 97 } 98 99 struct in6_addr * 100 prefixlen2mask6(uint8_t prefixlen) 101 { 102 static struct in6_addr mask; 103 int i; 104 105 memset(&mask, 0, sizeof(mask)); 106 for (i = 0; i < prefixlen / 8; i++) 107 mask.s6_addr[i] = 0xff; 108 i = prefixlen % 8; 109 if (i) 110 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 111 112 return (&mask); 113 } 114 115 void 116 eigrp_applymask(int af, union eigrpd_addr *dest, const union eigrpd_addr *src, 117 int prefixlen) 118 { 119 struct in6_addr mask; 120 int i; 121 122 switch (af) { 123 case AF_INET: 124 dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen); 125 break; 126 case AF_INET6: 127 memset(&mask, 0, sizeof(mask)); 128 for (i = 0; i < prefixlen / 8; i++) 129 mask.s6_addr[i] = 0xff; 130 i = prefixlen % 8; 131 if (i) 132 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 133 134 for (i = 0; i < 16; i++) 135 dest->v6.s6_addr[i] = src->v6.s6_addr[i] & 136 mask.s6_addr[i]; 137 break; 138 default: 139 fatalx("eigrp_applymask: unknown af"); 140 } 141 } 142 143 int 144 eigrp_addrcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b) 145 { 146 switch (af) { 147 case AF_INET: 148 if (a->v4.s_addr == b->v4.s_addr) 149 return (0); 150 return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1); 151 case AF_INET6: 152 return (!!memcmp(&a->v6, &b->v6, sizeof(struct in6_addr))); 153 default: 154 fatalx("eigrp_addrcmp: unknown af"); 155 } 156 } 157 158 int 159 eigrp_addrisset(int af, const union eigrpd_addr *addr) 160 { 161 switch (af) { 162 case AF_UNSPEC: 163 return (0); 164 case AF_INET: 165 if (addr->v4.s_addr != INADDR_ANY) 166 return (1); 167 break; 168 case AF_INET6: 169 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6)) 170 return (1); 171 break; 172 default: 173 fatalx("eigrp_addrisset: unknown af"); 174 } 175 176 return (0); 177 } 178 179 int 180 eigrp_prefixcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b, 181 uint8_t prefixlen) 182 { 183 in_addr_t mask, aa, ba; 184 int i; 185 uint8_t m; 186 187 switch (af) { 188 case AF_INET: 189 if (prefixlen == 0) 190 return (0); 191 if (prefixlen > 32) 192 fatalx("eigrp_prefixcmp: bad IPv4 prefixlen"); 193 mask = htonl(prefixlen2mask(prefixlen)); 194 aa = htonl(a->v4.s_addr) & mask; 195 ba = htonl(b->v4.s_addr) & mask; 196 return (aa - ba); 197 case AF_INET6: 198 if (prefixlen == 0) 199 return (0); 200 if (prefixlen > 128) 201 fatalx("eigrp_prefixcmp: bad IPv6 prefixlen"); 202 for (i = 0; i < prefixlen / 8; i++) 203 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 204 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 205 i = prefixlen % 8; 206 if (i) { 207 m = 0xff00 >> i; 208 if ((a->v6.s6_addr[prefixlen / 8] & m) != 209 (b->v6.s6_addr[prefixlen / 8] & m)) 210 return ((a->v6.s6_addr[prefixlen / 8] & m) - 211 (b->v6.s6_addr[prefixlen / 8] & m)); 212 } 213 return (0); 214 default: 215 fatalx("eigrp_prefixcmp: unknown af"); 216 } 217 return (-1); 218 } 219 220 int 221 bad_addr_v4(struct in_addr addr) 222 { 223 uint32_t a = ntohl(addr.s_addr); 224 225 if (((a >> IN_CLASSA_NSHIFT) == 0) || 226 ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) || 227 IN_MULTICAST(a) || IN_BADCLASS(a)) 228 return (1); 229 230 return (0); 231 } 232 233 int 234 bad_addr_v6(struct in6_addr *addr) 235 { 236 if (IN6_IS_ADDR_UNSPECIFIED(addr) || 237 IN6_IS_ADDR_LOOPBACK(addr) || 238 IN6_IS_ADDR_MULTICAST(addr) || 239 IN6_IS_ADDR_SITELOCAL(addr) || 240 IN6_IS_ADDR_V4MAPPED(addr) || 241 IN6_IS_ADDR_V4COMPAT(addr)) 242 return (1); 243 244 return (0); 245 } 246 247 int 248 bad_addr(int af, union eigrpd_addr *addr) 249 { 250 switch (af) { 251 case AF_INET: 252 return (bad_addr_v4(addr->v4)); 253 case AF_INET6: 254 return (bad_addr_v6(&addr->v6)); 255 default: 256 fatalx("bad_addr: unknown af"); 257 } 258 } 259 260 void 261 embedscope(struct sockaddr_in6 *sin6) 262 { 263 uint16_t tmp16; 264 265 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 266 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 267 if (tmp16 != 0) { 268 log_warnx("%s: address %s already has embeded scope %u", 269 __func__, log_sockaddr(sin6), ntohs(tmp16)); 270 } 271 tmp16 = htons(sin6->sin6_scope_id); 272 memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 273 sin6->sin6_scope_id = 0; 274 } 275 } 276 277 void 278 recoverscope(struct sockaddr_in6 *sin6) 279 { 280 uint16_t tmp16; 281 282 if (sin6->sin6_scope_id != 0) 283 log_warnx("%s: address %s already has scope id %u", 284 __func__, log_sockaddr(sin6), sin6->sin6_scope_id); 285 286 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 287 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 288 sin6->sin6_scope_id = ntohs(tmp16); 289 sin6->sin6_addr.s6_addr[2] = 0; 290 sin6->sin6_addr.s6_addr[3] = 0; 291 } 292 } 293 294 void 295 addscope(struct sockaddr_in6 *sin6, uint32_t id) 296 { 297 if (sin6->sin6_scope_id != 0) 298 log_warnx("%s: address %s already has scope id %u", __func__, 299 log_sockaddr(sin6), sin6->sin6_scope_id); 300 301 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) 302 sin6->sin6_scope_id = id; 303 } 304 305 void 306 clearscope(struct in6_addr *in6) 307 { 308 if (IN6_IS_SCOPE_EMBED(in6)) { 309 in6->s6_addr[2] = 0; 310 in6->s6_addr[3] = 0; 311 } 312 } 313 314 void 315 sa2addr(struct sockaddr *sa, int *af, union eigrpd_addr *addr) 316 { 317 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 318 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 319 320 memset(addr, 0, sizeof(*addr)); 321 switch (sa->sa_family) { 322 case AF_INET: 323 *af = AF_INET; 324 addr->v4 = sa_in->sin_addr; 325 break; 326 case AF_INET6: 327 *af = AF_INET6; 328 addr->v6 = sa_in6->sin6_addr; 329 break; 330 default: 331 fatalx("sa2addr: unknown af"); 332 } 333 } 334