1*3a50f0a9Sjmc /* $OpenBSD: util.c,v 1.4 2022/12/28 21:30:18 jmc Exp $ */
25e642944Sbluhm
35e642944Sbluhm /*
45e642944Sbluhm * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org>
55e642944Sbluhm * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
65e642944Sbluhm * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
75e642944Sbluhm *
85e642944Sbluhm * Permission to use, copy, modify, and distribute this software for any
95e642944Sbluhm * purpose with or without fee is hereby granted, provided that the above
105e642944Sbluhm * copyright notice and this permission notice appear in all copies.
115e642944Sbluhm *
125e642944Sbluhm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
135e642944Sbluhm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
145e642944Sbluhm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
155e642944Sbluhm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
165e642944Sbluhm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
175e642944Sbluhm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
185e642944Sbluhm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
195e642944Sbluhm */
205e642944Sbluhm
215e642944Sbluhm #include <netinet/in.h>
225e642944Sbluhm #include <string.h>
235e642944Sbluhm
245e642944Sbluhm #include "ospf6d.h"
255e642944Sbluhm #include "log.h"
265e642944Sbluhm
275e642944Sbluhm #define IN6_IS_SCOPE_EMBED(a) \
285e642944Sbluhm ((IN6_IS_ADDR_LINKLOCAL(a)) || \
295e642944Sbluhm (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \
305e642944Sbluhm (IN6_IS_ADDR_MC_INTFACELOCAL(a)))
315e642944Sbluhm
325e642944Sbluhm void
embedscope(struct sockaddr_in6 * sin6)335e642944Sbluhm embedscope(struct sockaddr_in6 *sin6)
345e642944Sbluhm {
355e642944Sbluhm u_int16_t tmp16;
365e642944Sbluhm
375e642944Sbluhm if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
385e642944Sbluhm bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
395e642944Sbluhm if (tmp16 != 0) {
40*3a50f0a9Sjmc log_warnx("embedscope: address %s already has embedded "
415e642944Sbluhm "scope %u", log_sockaddr(sin6), ntohs(tmp16));
425e642944Sbluhm }
435e642944Sbluhm tmp16 = htons(sin6->sin6_scope_id);
445e642944Sbluhm bcopy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
455e642944Sbluhm sin6->sin6_scope_id = 0;
465e642944Sbluhm }
475e642944Sbluhm }
485e642944Sbluhm
495e642944Sbluhm void
recoverscope(struct sockaddr_in6 * sin6)505e642944Sbluhm recoverscope(struct sockaddr_in6 *sin6)
515e642944Sbluhm {
525e642944Sbluhm u_int16_t tmp16;
535e642944Sbluhm
545e642944Sbluhm if (sin6->sin6_scope_id != 0) {
555e642944Sbluhm log_warnx("recoverscope: address %s already has scope id %u",
565e642944Sbluhm log_sockaddr(sin6), sin6->sin6_scope_id);
575e642944Sbluhm }
585e642944Sbluhm
595e642944Sbluhm if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
605e642944Sbluhm bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
615e642944Sbluhm sin6->sin6_scope_id = ntohs(tmp16);
625e642944Sbluhm sin6->sin6_addr.s6_addr[2] = 0;
635e642944Sbluhm sin6->sin6_addr.s6_addr[3] = 0;
645e642944Sbluhm }
655e642944Sbluhm }
665e642944Sbluhm
675e642944Sbluhm void
addscope(struct sockaddr_in6 * sin6,u_int32_t id)6875f178f9Sbluhm addscope(struct sockaddr_in6 *sin6, u_int32_t id)
6975f178f9Sbluhm {
7075f178f9Sbluhm if (sin6->sin6_scope_id != 0) {
7175f178f9Sbluhm log_warnx("addscope: address %s already has scope id %u",
7275f178f9Sbluhm log_sockaddr(sin6), sin6->sin6_scope_id);
7375f178f9Sbluhm }
7475f178f9Sbluhm
7575f178f9Sbluhm if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
7675f178f9Sbluhm sin6->sin6_scope_id = id;
7775f178f9Sbluhm }
7875f178f9Sbluhm }
7975f178f9Sbluhm
8075f178f9Sbluhm void
clearscope(struct in6_addr * in6)815e642944Sbluhm clearscope(struct in6_addr *in6)
825e642944Sbluhm {
835e642944Sbluhm if (IN6_IS_SCOPE_EMBED(in6)) {
845e642944Sbluhm in6->s6_addr[2] = 0;
855e642944Sbluhm in6->s6_addr[3] = 0;
865e642944Sbluhm }
875e642944Sbluhm }
885e642944Sbluhm
895e642944Sbluhm #undef IN6_IS_SCOPE_EMBED
905e642944Sbluhm
915e642944Sbluhm u_int8_t
mask2prefixlen(struct sockaddr_in6 * sa_in6)925e642944Sbluhm mask2prefixlen(struct sockaddr_in6 *sa_in6)
935e642944Sbluhm {
94976a8cd5Sremi u_int8_t *ap, *ep;
95976a8cd5Sremi u_int l = 0;
965e642944Sbluhm
975e642944Sbluhm /*
98*3a50f0a9Sjmc * sin6_len is the size of the sockaddr so subtract the offset of
995e642944Sbluhm * the possibly truncated sin6_addr struct.
1005e642944Sbluhm */
1015e642944Sbluhm ap = (u_int8_t *)&sa_in6->sin6_addr;
1025e642944Sbluhm ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
1035e642944Sbluhm for (; ap < ep; ap++) {
1045e642944Sbluhm /* this "beauty" is adopted from sbin/route/show.c ... */
1055e642944Sbluhm switch (*ap) {
1065e642944Sbluhm case 0xff:
1075e642944Sbluhm l += 8;
1085e642944Sbluhm break;
1095e642944Sbluhm case 0xfe:
1105e642944Sbluhm l += 7;
111976a8cd5Sremi goto done;
1125e642944Sbluhm case 0xfc:
1135e642944Sbluhm l += 6;
114976a8cd5Sremi goto done;
1155e642944Sbluhm case 0xf8:
1165e642944Sbluhm l += 5;
117976a8cd5Sremi goto done;
1185e642944Sbluhm case 0xf0:
1195e642944Sbluhm l += 4;
120976a8cd5Sremi goto done;
1215e642944Sbluhm case 0xe0:
1225e642944Sbluhm l += 3;
123976a8cd5Sremi goto done;
1245e642944Sbluhm case 0xc0:
1255e642944Sbluhm l += 2;
126976a8cd5Sremi goto done;
1275e642944Sbluhm case 0x80:
1285e642944Sbluhm l += 1;
129976a8cd5Sremi goto done;
1305e642944Sbluhm case 0x00:
131976a8cd5Sremi goto done;
1325e642944Sbluhm default:
1335e642944Sbluhm fatalx("non contiguous inet6 netmask");
1345e642944Sbluhm }
1355e642944Sbluhm }
1365e642944Sbluhm
137976a8cd5Sremi done:
138976a8cd5Sremi if (l > sizeof(struct in6_addr) * 8)
139976a8cd5Sremi fatalx("%s: prefixlen %d out of bound", __func__, l);
1405e642944Sbluhm return (l);
1415e642944Sbluhm }
1425e642944Sbluhm
1435e642944Sbluhm struct in6_addr *
prefixlen2mask(u_int8_t prefixlen)1445e642944Sbluhm prefixlen2mask(u_int8_t prefixlen)
1455e642944Sbluhm {
1465e642944Sbluhm static struct in6_addr mask;
1475e642944Sbluhm int i;
1485e642944Sbluhm
1495e642944Sbluhm bzero(&mask, sizeof(mask));
1505e642944Sbluhm for (i = 0; i < prefixlen / 8; i++)
1515e642944Sbluhm mask.s6_addr[i] = 0xff;
1525e642944Sbluhm i = prefixlen % 8;
1535e642944Sbluhm if (i)
1545e642944Sbluhm mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
1555e642944Sbluhm
1565e642944Sbluhm return (&mask);
1575e642944Sbluhm }
1585e642944Sbluhm
1595e642944Sbluhm void
inet6applymask(struct in6_addr * dest,const struct in6_addr * src,int prefixlen)1605e642944Sbluhm inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
1615e642944Sbluhm {
1625e642944Sbluhm struct in6_addr mask;
1635e642944Sbluhm int i;
1645e642944Sbluhm
1655e642944Sbluhm bzero(&mask, sizeof(mask));
1665e642944Sbluhm for (i = 0; i < prefixlen / 8; i++)
1675e642944Sbluhm mask.s6_addr[i] = 0xff;
1685e642944Sbluhm i = prefixlen % 8;
1695e642944Sbluhm if (i)
1705e642944Sbluhm mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
1715e642944Sbluhm
1725e642944Sbluhm for (i = 0; i < 16; i++)
1735e642944Sbluhm dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
1745e642944Sbluhm }
175