/* $OpenBSD: util.c,v 1.4 2022/12/28 21:30:18 jmc Exp $ */ /* * Copyright (c) 2012 Alexander Bluhm * Copyright (c) 2004 Esben Norby * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "ospf6d.h" #include "log.h" #define IN6_IS_SCOPE_EMBED(a) \ ((IN6_IS_ADDR_LINKLOCAL(a)) || \ (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \ (IN6_IS_ADDR_MC_INTFACELOCAL(a))) void embedscope(struct sockaddr_in6 *sin6) { u_int16_t tmp16; if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); if (tmp16 != 0) { log_warnx("embedscope: address %s already has embedded " "scope %u", log_sockaddr(sin6), ntohs(tmp16)); } tmp16 = htons(sin6->sin6_scope_id); bcopy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); sin6->sin6_scope_id = 0; } } void recoverscope(struct sockaddr_in6 *sin6) { u_int16_t tmp16; if (sin6->sin6_scope_id != 0) { log_warnx("recoverscope: address %s already has scope id %u", log_sockaddr(sin6), sin6->sin6_scope_id); } if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); sin6->sin6_scope_id = ntohs(tmp16); sin6->sin6_addr.s6_addr[2] = 0; sin6->sin6_addr.s6_addr[3] = 0; } } void addscope(struct sockaddr_in6 *sin6, u_int32_t id) { if (sin6->sin6_scope_id != 0) { log_warnx("addscope: address %s already has scope id %u", log_sockaddr(sin6), sin6->sin6_scope_id); } if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { sin6->sin6_scope_id = id; } } void clearscope(struct in6_addr *in6) { if (IN6_IS_SCOPE_EMBED(in6)) { in6->s6_addr[2] = 0; in6->s6_addr[3] = 0; } } #undef IN6_IS_SCOPE_EMBED u_int8_t mask2prefixlen(struct sockaddr_in6 *sa_in6) { u_int8_t *ap, *ep; u_int l = 0; /* * sin6_len is the size of the sockaddr so subtract the offset of * the possibly truncated sin6_addr struct. */ ap = (u_int8_t *)&sa_in6->sin6_addr; ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { case 0xff: l += 8; break; case 0xfe: l += 7; goto done; case 0xfc: l += 6; goto done; case 0xf8: l += 5; goto done; case 0xf0: l += 4; goto done; case 0xe0: l += 3; goto done; case 0xc0: l += 2; goto done; case 0x80: l += 1; goto done; case 0x00: goto done; default: fatalx("non contiguous inet6 netmask"); } } done: if (l > sizeof(struct in6_addr) * 8) fatalx("%s: prefixlen %d out of bound", __func__, l); return (l); } struct in6_addr * prefixlen2mask(u_int8_t prefixlen) { static struct in6_addr mask; int i; bzero(&mask, sizeof(mask)); for (i = 0; i < prefixlen / 8; i++) mask.s6_addr[i] = 0xff; i = prefixlen % 8; if (i) mask.s6_addr[prefixlen / 8] = 0xff00 >> i; return (&mask); } void inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) { struct in6_addr mask; int i; bzero(&mask, sizeof(mask)); for (i = 0; i < prefixlen / 8; i++) mask.s6_addr[i] = 0xff; i = prefixlen % 8; if (i) mask.s6_addr[prefixlen / 8] = 0xff00 >> i; for (i = 0; i < 16; i++) dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; }