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