1 /* $OpenBSD: util.c,v 1.5 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 #include <string.h> 24 25 #include "ldpd.h" 26 #include "log.h" 27 28 uint8_t 29 mask2prefixlen(in_addr_t ina) 30 { 31 if (ina == 0) 32 return (0); 33 else 34 return (33 - ffs(ntohl(ina))); 35 } 36 37 uint8_t 38 mask2prefixlen6(struct sockaddr_in6 *sa_in6) 39 { 40 unsigned int l = 0; 41 uint8_t *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 goto done; 58 case 0xfc: 59 l += 6; 60 goto done; 61 case 0xf8: 62 l += 5; 63 goto done; 64 case 0xf0: 65 l += 4; 66 goto done; 67 case 0xe0: 68 l += 3; 69 goto done; 70 case 0xc0: 71 l += 2; 72 goto done; 73 case 0x80: 74 l += 1; 75 goto done; 76 case 0x00: 77 goto done; 78 default: 79 fatalx("non contiguous inet6 netmask"); 80 } 81 } 82 83 done: 84 if (l > sizeof(struct in6_addr) * 8) 85 fatalx("inet6 prefixlen out of bound"); 86 return (l); 87 } 88 89 in_addr_t 90 prefixlen2mask(uint8_t prefixlen) 91 { 92 if (prefixlen == 0) 93 return (0); 94 95 return (htonl(0xffffffff << (32 - prefixlen))); 96 } 97 98 struct in6_addr * 99 prefixlen2mask6(uint8_t prefixlen) 100 { 101 static struct in6_addr mask; 102 int i; 103 104 memset(&mask, 0, sizeof(mask)); 105 for (i = 0; i < prefixlen / 8; i++) 106 mask.s6_addr[i] = 0xff; 107 i = prefixlen % 8; 108 if (i) 109 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 110 111 return (&mask); 112 } 113 114 void 115 ldp_applymask(int af, union ldpd_addr *dest, const union ldpd_addr *src, 116 int prefixlen) 117 { 118 struct in6_addr mask; 119 int i; 120 121 switch (af) { 122 case AF_INET: 123 dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen); 124 break; 125 case AF_INET6: 126 memset(&mask, 0, sizeof(mask)); 127 for (i = 0; i < prefixlen / 8; i++) 128 mask.s6_addr[i] = 0xff; 129 i = prefixlen % 8; 130 if (i) 131 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 132 133 for (i = 0; i < 16; i++) 134 dest->v6.s6_addr[i] = src->v6.s6_addr[i] & 135 mask.s6_addr[i]; 136 break; 137 default: 138 fatalx("ldp_applymask: unknown af"); 139 } 140 } 141 142 int 143 ldp_addrcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b) 144 { 145 switch (af) { 146 case AF_INET: 147 if (a->v4.s_addr == b->v4.s_addr) 148 return (0); 149 return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1); 150 case AF_INET6: 151 return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr))); 152 default: 153 fatalx("ldp_addrcmp: unknown af"); 154 } 155 } 156 157 int 158 ldp_addrisset(int af, const union ldpd_addr *addr) 159 { 160 switch (af) { 161 case AF_UNSPEC: 162 return (0); 163 case AF_INET: 164 if (addr->v4.s_addr != INADDR_ANY) 165 return (1); 166 break; 167 case AF_INET6: 168 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6)) 169 return (1); 170 break; 171 default: 172 fatalx("ldp_addrisset: unknown af"); 173 } 174 175 return (0); 176 } 177 178 int 179 ldp_prefixcmp(int af, const union ldpd_addr *a, const union ldpd_addr *b, 180 uint8_t prefixlen) 181 { 182 in_addr_t mask, aa, ba; 183 int i; 184 uint8_t m; 185 186 switch (af) { 187 case AF_INET: 188 if (prefixlen == 0) 189 return (0); 190 if (prefixlen > 32) 191 fatalx("ldp_prefixcmp: bad IPv4 prefixlen"); 192 mask = htonl(prefixlen2mask(prefixlen)); 193 aa = htonl(a->v4.s_addr) & mask; 194 ba = htonl(b->v4.s_addr) & mask; 195 return (aa - ba); 196 case AF_INET6: 197 if (prefixlen == 0) 198 return (0); 199 if (prefixlen > 128) 200 fatalx("ldp_prefixcmp: bad IPv6 prefixlen"); 201 for (i = 0; i < prefixlen / 8; i++) 202 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 203 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 204 i = prefixlen % 8; 205 if (i) { 206 m = 0xff00 >> i; 207 if ((a->v6.s6_addr[prefixlen / 8] & m) != 208 (b->v6.s6_addr[prefixlen / 8] & m)) 209 return ((a->v6.s6_addr[prefixlen / 8] & m) - 210 (b->v6.s6_addr[prefixlen / 8] & m)); 211 } 212 return (0); 213 default: 214 fatalx("ldp_prefixcmp: unknown af"); 215 } 216 return (-1); 217 } 218 219 int 220 bad_addr_v4(struct in_addr addr) 221 { 222 uint32_t a = ntohl(addr.s_addr); 223 224 if (((a >> IN_CLASSA_NSHIFT) == 0) || 225 ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) || 226 IN_MULTICAST(a) || IN_BADCLASS(a)) 227 return (1); 228 229 return (0); 230 } 231 232 int 233 bad_addr_v6(struct in6_addr *addr) 234 { 235 if (IN6_IS_ADDR_UNSPECIFIED(addr) || 236 IN6_IS_ADDR_LOOPBACK(addr) || 237 IN6_IS_ADDR_MULTICAST(addr) || 238 IN6_IS_ADDR_SITELOCAL(addr) || 239 IN6_IS_ADDR_V4MAPPED(addr) || 240 IN6_IS_ADDR_V4COMPAT(addr)) 241 return (1); 242 243 return (0); 244 } 245 246 int 247 bad_addr(int af, union ldpd_addr *addr) 248 { 249 switch (af) { 250 case AF_INET: 251 return (bad_addr_v4(addr->v4)); 252 case AF_INET6: 253 return (bad_addr_v6(&addr->v6)); 254 default: 255 fatalx("bad_addr: unknown af"); 256 } 257 } 258 259 void 260 embedscope(struct sockaddr_in6 *sin6) 261 { 262 uint16_t tmp16; 263 264 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 265 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 266 if (tmp16 != 0) { 267 log_warnx("%s: address %s already has embeded scope %u", 268 __func__, log_sockaddr(sin6), ntohs(tmp16)); 269 } 270 tmp16 = htons(sin6->sin6_scope_id); 271 memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 272 sin6->sin6_scope_id = 0; 273 } 274 } 275 276 void 277 recoverscope(struct sockaddr_in6 *sin6) 278 { 279 uint16_t tmp16; 280 281 if (sin6->sin6_scope_id != 0) 282 log_warnx("%s: address %s already has scope id %u", 283 __func__, log_sockaddr(sin6), sin6->sin6_scope_id); 284 285 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 286 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 287 sin6->sin6_scope_id = ntohs(tmp16); 288 sin6->sin6_addr.s6_addr[2] = 0; 289 sin6->sin6_addr.s6_addr[3] = 0; 290 } 291 } 292 293 void 294 addscope(struct sockaddr_in6 *sin6, uint32_t id) 295 { 296 if (sin6->sin6_scope_id != 0) 297 log_warnx("%s: address %s already has scope id %u", __func__, 298 log_sockaddr(sin6), sin6->sin6_scope_id); 299 300 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) 301 sin6->sin6_scope_id = id; 302 } 303 304 void 305 clearscope(struct in6_addr *in6) 306 { 307 if (IN6_IS_SCOPE_EMBED(in6)) { 308 in6->s6_addr[2] = 0; 309 in6->s6_addr[3] = 0; 310 } 311 } 312 313 struct sockaddr * 314 addr2sa(int af, union ldpd_addr *addr, uint16_t port) 315 { 316 static struct sockaddr_storage ss; 317 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 318 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 319 320 memset(&ss, 0, sizeof(ss)); 321 switch (af) { 322 case AF_INET: 323 sa_in->sin_family = AF_INET; 324 sa_in->sin_len = sizeof(struct sockaddr_in); 325 sa_in->sin_addr = addr->v4; 326 sa_in->sin_port = htons(port); 327 break; 328 case AF_INET6: 329 sa_in6->sin6_family = AF_INET6; 330 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 331 sa_in6->sin6_addr = addr->v6; 332 sa_in6->sin6_port = htons(port); 333 break; 334 default: 335 fatalx("addr2sa: unknown af"); 336 } 337 338 return ((struct sockaddr *)&ss); 339 } 340 341 void 342 sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr) 343 { 344 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 345 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 346 347 memset(addr, 0, sizeof(*addr)); 348 switch (sa->sa_family) { 349 case AF_INET: 350 *af = AF_INET; 351 addr->v4 = sa_in->sin_addr; 352 break; 353 case AF_INET6: 354 *af = AF_INET6; 355 addr->v6 = sa_in6->sin6_addr; 356 break; 357 default: 358 fatalx("sa2addr: unknown af"); 359 } 360 } 361