1/* $OpenBSD: util.c,v 1.12 2022/12/28 21:30:16 jmc 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 29uint8_t 30mask2prefixlen(in_addr_t ina) 31{ 32 if (ina == 0) 33 return (0); 34 else 35 return (33 - ffs(ntohl(ina))); 36} 37 38uint8_t 39mask2prefixlen6(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 subtract 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 84done: 85 if (l > sizeof(struct in6_addr) * 8) 86 fatalx("inet6 prefixlen out of bound"); 87 return (l); 88} 89 90in_addr_t 91prefixlen2mask(uint8_t prefixlen) 92{ 93 if (prefixlen == 0) 94 return (0); 95 96 return (htonl(0xffffffff << (32 - prefixlen))); 97} 98 99struct in6_addr * 100prefixlen2mask6(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 115void 116eigrp_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 143int 144eigrp_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 158int 159eigrp_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 179int 180eigrp_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 220int 221bad_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)) 228 return (1); 229 230 return (0); 231} 232 233int 234bad_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 247int 248bad_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 260void 261embedscope(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 embedded 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 277void 278recoverscope(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 294void 295addscope(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 305void 306clearscope(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 314void 315sa2addr(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