1 /* $OpenBSD: util.c,v 1.8 2018/12/03 18:39:42 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Martin Pieuchot 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /* 19 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. Neither the name of the project nor the names of its contributors 31 * may be used to endorse or promote products derived from this software 32 * without specific prior written permission. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 */ 46 47 #include "srp_compat.h" 48 49 #include <sys/socket.h> 50 #include <sys/domain.h> 51 #include <sys/queue.h> 52 #include <sys/srp.h> 53 54 #include <net/rtable.h> 55 #include <net/route.h> 56 57 #include <netinet/in.h> 58 #include <arpa/inet.h> 59 60 #include <assert.h> 61 #include <err.h> 62 #include <stddef.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 67 #include "util.h" 68 69 struct sockaddr *rt_plen2mask(struct rtentry *, struct sockaddr_in6 *); 70 71 struct domain inetdomain = { 72 .dom_family = AF_INET, 73 .dom_name = "inet", 74 .dom_init = NULL, 75 .dom_externalize = NULL, 76 .dom_dispose = NULL, 77 .dom_protosw = NULL, 78 .dom_protoswNPROTOSW = NULL, 79 .dom_rtoffset = offsetof(struct sockaddr_in, sin_addr), 80 .dom_maxplen = 32, 81 .dom_ifattach = NULL, 82 .dom_ifdetach = NULL, 83 }; 84 85 struct domain inet6domain = { 86 .dom_family = AF_INET6, 87 .dom_name = "inet6", 88 .dom_init = NULL, 89 .dom_externalize = NULL, 90 .dom_dispose = NULL, 91 .dom_protosw = NULL, 92 .dom_protoswNPROTOSW = NULL, 93 .dom_rtoffset = offsetof(struct sockaddr_in6, sin6_addr), 94 .dom_maxplen = 128, 95 .dom_ifattach = NULL, 96 .dom_ifdetach = NULL, 97 }; 98 99 struct domain *domains[] = { &inetdomain, &inet6domain, NULL }; 100 101 /* 102 * Insert a route from a string containing a destination: "192.168.1/24" 103 */ 104 void 105 route_insert(unsigned int rid, sa_family_t af, char *string) 106 { 107 struct sockaddr_storage ss, ms; 108 struct sockaddr *ndst, *dst = (struct sockaddr *)&ss; 109 struct sockaddr *mask = (struct sockaddr *)&ms; 110 struct rtentry *rt, *nrt; 111 char ip[INET6_ADDRSTRLEN]; 112 int plen, error; 113 114 rt = calloc(1, sizeof(*rt)); 115 if (rt == NULL) 116 errx(1, "out of memory"); 117 118 plen = inet_net_ptosa(af, string, dst, mask); 119 if (plen == -1) 120 err(1, "wrong line: %s", string); 121 122 /* Normalize sockaddr a la rtrequest1(9) */ 123 ndst = malloc(dst->sa_len); 124 if (ndst == NULL) 125 errx(1, "out of memory"); 126 rt_maskedcopy(dst, ndst, mask); 127 128 if ((error = rtable_insert(rid, ndst, mask, NULL, 0, rt)) != 0) { 129 inet_net_satop(af, ndst, plen, ip, sizeof(ip)); 130 errx(1, "can't add route: %s, %s\n", ip, strerror(error)); 131 } 132 nrt = rtable_lookup(rid, dst, mask, NULL, RTP_ANY); 133 if (nrt != rt) { 134 inet_net_satop(af, rt_key(rt), plen, ip, sizeof(ip)); 135 errx(1, "added route not found: %s\n", ip); 136 } 137 } 138 139 /* 140 * Delete a route from a string containing a destination: "192.168.1/24" 141 */ 142 void 143 route_delete(unsigned int rid, sa_family_t af, char *string) 144 { 145 struct sockaddr_storage ss, ms; 146 struct sockaddr *dst = (struct sockaddr *)&ss; 147 struct sockaddr *mask = (struct sockaddr *)&ms; 148 struct rtentry *rt, *nrt; 149 char ip[INET6_ADDRSTRLEN]; 150 int plen, error; 151 152 plen = inet_net_ptosa(af, string, dst, mask); 153 if (plen == -1) 154 err(1, "wrong line: %s", string); 155 156 rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 157 if (rt == NULL) { 158 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 159 errx(1, "can't find route: %s\n", ip); 160 } 161 162 assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0); 163 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 164 165 if ((error = rtable_delete(0, dst, mask, rt)) != 0) { 166 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 167 errx(1, "can't rm route: %s, %s\n", ip, strerror(error)); 168 } 169 170 nrt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 171 if (nrt != NULL) { 172 char ip0[INET6_ADDRSTRLEN]; 173 inet_net_satop(af, rt_key(nrt), plen, ip, sizeof(ip)); 174 inet_net_satop(af, rt_key(rt), plen, ip0, sizeof(ip0)); 175 errx(1, "found: %s after deleting: %s", ip, ip0); 176 } 177 178 free(rt_key(rt)); 179 free(rt); 180 } 181 182 /* 183 * Lookup a route from a string containing a destination: "192.168.1/24" 184 */ 185 void 186 route_lookup(unsigned int rid, sa_family_t af, char *string) 187 { 188 struct sockaddr_storage ss, ms; 189 struct sockaddr *dst = (struct sockaddr *)&ss; 190 struct sockaddr *mask = (struct sockaddr *)&ms; 191 struct rtentry *rt; 192 char ip[INET6_ADDRSTRLEN]; 193 int plen; 194 195 plen = inet_net_ptosa(af, string, dst, mask); 196 if (plen == -1) 197 err(1, "wrong line: %s", string); 198 199 rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 200 if (rt == NULL) { 201 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 202 errx(1, "%s not found\n", ip); 203 } 204 assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0); 205 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 206 } 207 208 int 209 do_from_file(unsigned int rid, sa_family_t af, char *filename, 210 void (*func)(unsigned int, sa_family_t, char *)) 211 { 212 FILE *fp; 213 char *buf; 214 size_t len; 215 int lines = 0; 216 217 if ((fp = fopen(filename, "r")) == NULL) 218 errx(1, "No such file: %s\n", filename); 219 220 while ((buf = fgetln(fp, &len)) != NULL) { 221 if (buf[len - 1] == '\n') 222 buf[len - 1] = '\0'; 223 224 (*func)(rid, af, buf); 225 lines++; 226 } 227 fclose(fp); 228 229 return (lines); 230 } 231 232 int 233 rtentry_dump(struct rtentry *rt, void *w, unsigned int rid) 234 { 235 char dest[INET6_ADDRSTRLEN]; 236 sa_family_t af = rt_key(rt)->sa_family; 237 238 inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest)); 239 printf("%s\n", dest); 240 241 return (0); 242 } 243 244 int 245 rtentry_delete(struct rtentry *rt, void *w, unsigned int rid) 246 { 247 char dest[INET6_ADDRSTRLEN]; 248 sa_family_t af = rt_key(rt)->sa_family; 249 struct sockaddr_in6 sa_mask; 250 struct sockaddr *mask = rt_plen2mask(rt, &sa_mask); 251 int error; 252 253 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 254 255 if ((error = rtable_delete(0, rt_key(rt), mask, rt)) != 0) { 256 inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest)); 257 errx(1, "can't rm route: %s, %s\n", dest, strerror(error)); 258 } 259 260 return (0); 261 } 262 263 void 264 rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, 265 struct sockaddr *netmask) 266 { 267 uint8_t *cp1 = (uint8_t *)src; 268 uint8_t *cp2 = (uint8_t *)dst; 269 uint8_t *cp3 = (uint8_t *)netmask; 270 uint8_t *cplim = cp2 + *cp3; 271 uint8_t *cplim2 = cp2 + *cp1; 272 273 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 274 cp3 += 2; 275 if (cplim > cplim2) 276 cplim = cplim2; 277 while (cp2 < cplim) 278 *cp2++ = *cp1++ & *cp3++; 279 if (cp2 < cplim2) 280 memset(cp2, 0, (unsigned int)(cplim2 - cp2)); 281 } 282 283 void 284 in_prefixlen2mask(struct in_addr *maskp, int plen) 285 { 286 if (plen == 0) 287 maskp->s_addr = 0; 288 else 289 maskp->s_addr = htonl(0xffffffff << (32 - plen)); 290 } 291 292 void 293 in6_prefixlen2mask(struct in6_addr *maskp, int len) 294 { 295 uint8_t maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 296 int bytelen, bitlen, i; 297 298 assert(0 <= len && len <= 128); 299 300 memset(maskp, 0, sizeof(*maskp)); 301 bytelen = len / 8; 302 bitlen = len % 8; 303 for (i = 0; i < bytelen; i++) 304 maskp->s6_addr[i] = 0xff; 305 /* len == 128 is ok because bitlen == 0 then */ 306 if (bitlen) 307 maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 308 } 309 310 struct sockaddr * 311 rt_plentosa(sa_family_t af, int plen, struct sockaddr_in6 *sa_mask) 312 { 313 struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; 314 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; 315 316 assert(plen >= 0 || plen == -1); 317 318 if (plen == -1) 319 return (NULL); 320 321 memset(sa_mask, 0, sizeof(*sa_mask)); 322 323 switch (af) { 324 case AF_INET: 325 sin->sin_family = AF_INET; 326 sin->sin_len = sizeof(struct sockaddr_in); 327 in_prefixlen2mask(&sin->sin_addr, plen); 328 break; 329 case AF_INET6: 330 sin6->sin6_family = AF_INET6; 331 sin6->sin6_len = sizeof(struct sockaddr_in6); 332 in6_prefixlen2mask(&sin6->sin6_addr, plen); 333 break; 334 default: 335 return (NULL); 336 } 337 338 return ((struct sockaddr *)sa_mask); 339 } 340 341 struct sockaddr * 342 rt_plen2mask(struct rtentry *rt, struct sockaddr_in6 *sa_mask) 343 { 344 #ifndef ART 345 return (rt_mask(rt)); 346 #else 347 return (rt_plentosa(rt_key(rt)->sa_family, rt_plen(rt), sa_mask)); 348 #endif /* ART */ 349 } 350 351 352 int 353 inet_net_ptosa(sa_family_t af, const char *buf, struct sockaddr *sa, 354 struct sockaddr *ma) 355 { 356 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 357 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 358 int i, plen; 359 360 switch (af) { 361 case AF_INET: 362 memset(sin, 0, sizeof(*sin)); 363 sin->sin_family = af; 364 sin->sin_len = sizeof(*sin); 365 plen = inet_net_pton(af, buf, &sin->sin_addr, 366 sizeof(sin->sin_addr)); 367 if (plen == -1 || ma == NULL) 368 break; 369 370 sin = (struct sockaddr_in *)ma; 371 memset(sin, 0, sizeof(*sin)); 372 sin->sin_len = sizeof(*sin); 373 sin->sin_family = 0; 374 in_prefixlen2mask(&sin->sin_addr, plen); 375 break; 376 case AF_INET6: 377 memset(sin6, 0, sizeof(*sin6)); 378 sin6->sin6_family = af; 379 sin6->sin6_len = sizeof(*sin6); 380 plen = inet_net_pton(af, buf, &sin6->sin6_addr, 381 sizeof(sin6->sin6_addr)); 382 if (plen == -1 || ma == NULL) 383 break; 384 385 sin6 = (struct sockaddr_in6 *)ma; 386 memset(sin6, 0, sizeof(*sin6)); 387 sin6->sin6_len = sizeof(*sin6); 388 sin6->sin6_family = 0; 389 for (i = 0; i < plen / 8; i++) 390 sin6->sin6_addr.s6_addr[i] = 0xff; 391 i = plen % 8; 392 if (i) 393 sin6->sin6_addr.s6_addr[plen / 8] = 0xff00 >> i; 394 break; 395 default: 396 plen = -1; 397 } 398 399 return (plen); 400 } 401 402 /* 403 * Only compare the address fields, we cannot use memcmp(3) because 404 * the radix tree abuses the first fields of the mask sockaddr for 405 * a different purpose. 406 */ 407 int 408 maskcmp(sa_family_t af, struct sockaddr *sa1, struct sockaddr *sa2) 409 { 410 struct sockaddr_in *sin1, *sin2; 411 struct sockaddr_in6 *sin61, *sin62; 412 int len; 413 414 switch (af) { 415 case AF_INET: 416 sin1 = (struct sockaddr_in *)sa1; 417 sin2 = (struct sockaddr_in *)sa2; 418 len = sizeof(sin1->sin_addr); 419 return memcmp(&sin1->sin_addr, &sin2->sin_addr, len); 420 case AF_INET6: 421 sin61 = (struct sockaddr_in6 *)sa1; 422 sin62 = (struct sockaddr_in6 *)sa2; 423 len = sizeof(sin61->sin6_addr); 424 return memcmp(&sin61->sin6_addr, &sin62->sin6_addr, len); 425 default: 426 return (-1); 427 } 428 } 429 430 char * 431 inet_net_satop(sa_family_t af, struct sockaddr *sa, int plen, char *buf, 432 size_t len) 433 { 434 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 435 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 436 437 switch (af) { 438 case AF_INET: 439 return inet_net_ntop(af, &sin->sin_addr, plen, buf, len); 440 case AF_INET6: 441 return inet_net_ntop(af, &sin6->sin6_addr, plen, buf, len); 442 default: 443 return (NULL); 444 } 445 } 446 447 /* Give some jitter to hash, to avoid synchronization between routers. */ 448 static uint32_t rt_hashjitter; 449 450 /* 451 * Originated from bridge_hash() in if_bridge.c 452 */ 453 #define mix(a, b, c) do { \ 454 a -= b; a -= c; a ^= (c >> 13); \ 455 b -= c; b -= a; b ^= (a << 8); \ 456 c -= a; c -= b; c ^= (b >> 13); \ 457 a -= b; a -= c; a ^= (c >> 12); \ 458 b -= c; b -= a; b ^= (a << 16); \ 459 c -= a; c -= b; c ^= (b >> 5); \ 460 a -= b; a -= c; a ^= (c >> 3); \ 461 b -= c; b -= a; b ^= (a << 10); \ 462 c -= a; c -= b; c ^= (b >> 15); \ 463 } while (0) 464 465 int 466 rt_hash(struct rtentry *rt, struct sockaddr *dst, uint32_t *src) 467 { 468 uint32_t a, b, c; 469 470 while (rt_hashjitter == 0) 471 rt_hashjitter = arc4random(); 472 473 if (src == NULL) 474 return (-1); 475 476 a = b = 0x9e3779b9; 477 c = rt_hashjitter; 478 479 switch (dst->sa_family) { 480 case AF_INET: 481 { 482 struct sockaddr_in *sin; 483 484 sin = satosin(dst); 485 a += sin->sin_addr.s_addr; 486 b += (src != NULL) ? src[0] : 0; 487 mix(a, b, c); 488 break; 489 } 490 #ifdef INET6 491 case AF_INET6: 492 { 493 struct sockaddr_in6 *sin6; 494 495 sin6 = satosin6(dst); 496 a += sin6->sin6_addr.s6_addr32[0]; 497 b += sin6->sin6_addr.s6_addr32[2]; 498 c += (src != NULL) ? src[0] : 0; 499 mix(a, b, c); 500 a += sin6->sin6_addr.s6_addr32[1]; 501 b += sin6->sin6_addr.s6_addr32[3]; 502 c += (src != NULL) ? src[1] : 0; 503 mix(a, b, c); 504 a += sin6->sin6_addr.s6_addr32[2]; 505 b += sin6->sin6_addr.s6_addr32[1]; 506 c += (src != NULL) ? src[2] : 0; 507 mix(a, b, c); 508 a += sin6->sin6_addr.s6_addr32[3]; 509 b += sin6->sin6_addr.s6_addr32[0]; 510 c += (src != NULL) ? src[3] : 0; 511 mix(a, b, c); 512 break; 513 } 514 #endif /* INET6 */ 515 } 516 517 return (c & 0xffff); 518 } 519