1 /* $OpenBSD: util.c,v 1.3 2018/12/09 14:56:24 remi Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <netinet/in.h> 22 #include <string.h> 23 24 #include "ospf6d.h" 25 #include "log.h" 26 27 #define IN6_IS_SCOPE_EMBED(a) \ 28 ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 29 (IN6_IS_ADDR_MC_LINKLOCAL(a)) || \ 30 (IN6_IS_ADDR_MC_INTFACELOCAL(a))) 31 32 void 33 embedscope(struct sockaddr_in6 *sin6) 34 { 35 u_int16_t tmp16; 36 37 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 38 bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 39 if (tmp16 != 0) { 40 log_warnx("embedscope: address %s already has embeded " 41 "scope %u", log_sockaddr(sin6), ntohs(tmp16)); 42 } 43 tmp16 = htons(sin6->sin6_scope_id); 44 bcopy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16)); 45 sin6->sin6_scope_id = 0; 46 } 47 } 48 49 void 50 recoverscope(struct sockaddr_in6 *sin6) 51 { 52 u_int16_t tmp16; 53 54 if (sin6->sin6_scope_id != 0) { 55 log_warnx("recoverscope: address %s already has scope id %u", 56 log_sockaddr(sin6), sin6->sin6_scope_id); 57 } 58 59 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 60 bcopy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16)); 61 sin6->sin6_scope_id = ntohs(tmp16); 62 sin6->sin6_addr.s6_addr[2] = 0; 63 sin6->sin6_addr.s6_addr[3] = 0; 64 } 65 } 66 67 void 68 addscope(struct sockaddr_in6 *sin6, u_int32_t id) 69 { 70 if (sin6->sin6_scope_id != 0) { 71 log_warnx("addscope: address %s already has scope id %u", 72 log_sockaddr(sin6), sin6->sin6_scope_id); 73 } 74 75 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) { 76 sin6->sin6_scope_id = id; 77 } 78 } 79 80 void 81 clearscope(struct in6_addr *in6) 82 { 83 if (IN6_IS_SCOPE_EMBED(in6)) { 84 in6->s6_addr[2] = 0; 85 in6->s6_addr[3] = 0; 86 } 87 } 88 89 #undef IN6_IS_SCOPE_EMBED 90 91 u_int8_t 92 mask2prefixlen(struct sockaddr_in6 *sa_in6) 93 { 94 u_int8_t *ap, *ep; 95 u_int l = 0; 96 97 /* 98 * sin6_len is the size of the sockaddr so substract the offset of 99 * the possibly truncated sin6_addr struct. 100 */ 101 ap = (u_int8_t *)&sa_in6->sin6_addr; 102 ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; 103 for (; ap < ep; ap++) { 104 /* this "beauty" is adopted from sbin/route/show.c ... */ 105 switch (*ap) { 106 case 0xff: 107 l += 8; 108 break; 109 case 0xfe: 110 l += 7; 111 goto done; 112 case 0xfc: 113 l += 6; 114 goto done; 115 case 0xf8: 116 l += 5; 117 goto done; 118 case 0xf0: 119 l += 4; 120 goto done; 121 case 0xe0: 122 l += 3; 123 goto done; 124 case 0xc0: 125 l += 2; 126 goto done; 127 case 0x80: 128 l += 1; 129 goto done; 130 case 0x00: 131 goto done; 132 default: 133 fatalx("non contiguous inet6 netmask"); 134 } 135 } 136 137 done: 138 if (l > sizeof(struct in6_addr) * 8) 139 fatalx("%s: prefixlen %d out of bound", __func__, l); 140 return (l); 141 } 142 143 struct in6_addr * 144 prefixlen2mask(u_int8_t prefixlen) 145 { 146 static struct in6_addr mask; 147 int i; 148 149 bzero(&mask, sizeof(mask)); 150 for (i = 0; i < prefixlen / 8; i++) 151 mask.s6_addr[i] = 0xff; 152 i = prefixlen % 8; 153 if (i) 154 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 155 156 return (&mask); 157 } 158 159 void 160 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 161 { 162 struct in6_addr mask; 163 int i; 164 165 bzero(&mask, sizeof(mask)); 166 for (i = 0; i < prefixlen / 8; i++) 167 mask.s6_addr[i] = 0xff; 168 i = prefixlen % 8; 169 if (i) 170 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 171 172 for (i = 0; i < 16; i++) 173 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 174 } 175