1 /* $OpenBSD: util.c,v 1.15 2024/08/23 12:56:26 anton 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 #define _KERNEL 48 #include <sys/refcnt.h> 49 #undef _KERNEL 50 51 #include "srp_compat.h" 52 53 #include <sys/socket.h> 54 #include <sys/domain.h> 55 #include <sys/queue.h> 56 #include <sys/srp.h> 57 58 #include <net/rtable.h> 59 #define _KERNEL 60 #include <net/route.h> 61 #undef _KERNEL 62 63 #include <netinet/in.h> 64 #include <arpa/inet.h> 65 66 #include <assert.h> 67 #include <err.h> 68 #include <stddef.h> 69 #include <stdio.h> 70 #include <stdlib.h> 71 #include <string.h> 72 73 #include "util.h" 74 75 struct sockaddr *rt_plen2mask(struct rtentry *, struct sockaddr_in6 *); 76 77 struct domain inetdomain = { 78 .dom_family = AF_INET, 79 .dom_name = "inet", 80 .dom_init = NULL, 81 .dom_externalize = NULL, 82 .dom_dispose = NULL, 83 .dom_protosw = NULL, 84 .dom_protoswNPROTOSW = NULL, 85 .dom_rtoffset = offsetof(struct sockaddr_in, sin_addr), 86 .dom_maxplen = 32, 87 }; 88 89 struct domain inet6domain = { 90 .dom_family = AF_INET6, 91 .dom_name = "inet6", 92 .dom_init = NULL, 93 .dom_externalize = NULL, 94 .dom_dispose = NULL, 95 .dom_protosw = NULL, 96 .dom_protoswNPROTOSW = NULL, 97 .dom_rtoffset = offsetof(struct sockaddr_in6, sin6_addr), 98 .dom_maxplen = 128, 99 }; 100 101 struct domain *domains[] = { &inetdomain, &inet6domain, NULL }; 102 103 /* 104 * Insert a route from a string containing a destination: "192.168.1/24" 105 */ 106 void 107 route_insert(unsigned int rid, sa_family_t af, char *string) 108 { 109 struct sockaddr_storage ss, ms; 110 struct sockaddr *ndst, *dst = (struct sockaddr *)&ss; 111 struct sockaddr *mask = (struct sockaddr *)&ms; 112 struct rtentry *rt, *nrt; 113 char ip[INET6_ADDRSTRLEN]; 114 int plen, error; 115 116 rt = calloc(1, sizeof(*rt)); 117 if (rt == NULL) 118 errx(1, "out of memory"); 119 refcnt_init(&rt->rt_refcnt); 120 121 plen = inet_net_ptosa(af, string, dst, mask); 122 if (plen == -1) 123 err(1, "wrong line: %s", string); 124 125 /* Normalize sockaddr a la rtrequest1(9) */ 126 ndst = malloc(dst->sa_len); 127 if (ndst == NULL) 128 errx(1, "out of memory"); 129 rt_maskedcopy(dst, ndst, mask); 130 131 if ((error = rtable_insert(rid, ndst, mask, NULL, 0, rt)) != 0) { 132 inet_net_satop(af, ndst, plen, ip, sizeof(ip)); 133 errx(1, "can't add route: %s, %s", ip, strerror(error)); 134 } 135 nrt = rtable_lookup(rid, dst, mask, NULL, RTP_ANY); 136 if (nrt != rt) { 137 inet_net_satop(af, rt_key(rt), plen, ip, sizeof(ip)); 138 errx(1, "added route not found: %s", ip); 139 } 140 rtfree(rt); 141 rtfree(nrt); 142 } 143 144 /* 145 * Delete a route from a string containing a destination: "192.168.1/24" 146 */ 147 void 148 route_delete(unsigned int rid, sa_family_t af, char *string) 149 { 150 struct sockaddr_storage ss, ms; 151 struct sockaddr *dst = (struct sockaddr *)&ss; 152 struct sockaddr *mask = (struct sockaddr *)&ms; 153 struct rtentry *rt, *nrt; 154 char ip[INET6_ADDRSTRLEN]; 155 int plen, error; 156 157 plen = inet_net_ptosa(af, string, dst, mask); 158 if (plen == -1) 159 err(1, "wrong line: %s", string); 160 161 rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 162 if (rt == NULL) { 163 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 164 errx(1, "can't find route: %s", ip); 165 } 166 167 assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0); 168 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 169 170 if ((error = rtable_delete(0, dst, mask, rt)) != 0) { 171 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 172 errx(1, "can't rm route: %s, %s", ip, strerror(error)); 173 } 174 175 nrt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 176 if (nrt != NULL) { 177 char ip0[INET6_ADDRSTRLEN]; 178 inet_net_satop(af, rt_key(nrt), plen, ip, sizeof(ip)); 179 inet_net_satop(af, rt_key(rt), plen, ip0, sizeof(ip0)); 180 errx(1, "found: %s after deleting: %s", ip, ip0); 181 } 182 183 rtfree(rt); 184 assert(refcnt_read(&rt->rt_refcnt) == 0); 185 186 free(rt_key(rt)); 187 free(rt); 188 } 189 190 /* 191 * Lookup a route from a string containing a destination: "192.168.1/24" 192 */ 193 void 194 route_lookup(unsigned int rid, sa_family_t af, char *string) 195 { 196 struct sockaddr_storage ss, ms; 197 struct sockaddr *dst = (struct sockaddr *)&ss; 198 struct sockaddr *mask = (struct sockaddr *)&ms; 199 struct rtentry *rt; 200 char ip[INET6_ADDRSTRLEN]; 201 int plen; 202 203 plen = inet_net_ptosa(af, string, dst, mask); 204 if (plen == -1) 205 err(1, "wrong line: %s", string); 206 207 rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 208 if (rt == NULL) { 209 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 210 errx(1, "%s not found", ip); 211 } 212 assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0); 213 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 214 215 rtfree(rt); 216 } 217 218 int 219 do_from_file(unsigned int rid, sa_family_t af, char *filename, 220 void (*func)(unsigned int, sa_family_t, char *)) 221 { 222 FILE *fp; 223 char *buf; 224 size_t len; 225 int lines = 0; 226 227 if ((fp = fopen(filename, "r")) == NULL) 228 errx(1, "No such file: %s", filename); 229 230 while ((buf = fgetln(fp, &len)) != NULL) { 231 if (buf[len - 1] == '\n') 232 buf[len - 1] = '\0'; 233 234 (*func)(rid, af, buf); 235 lines++; 236 } 237 fclose(fp); 238 239 return (lines); 240 } 241 242 int 243 rtentry_dump(struct rtentry *rt, void *w, unsigned int rid) 244 { 245 char dest[INET6_ADDRSTRLEN]; 246 sa_family_t af = rt_key(rt)->sa_family; 247 248 inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest)); 249 printf("%s\n", dest); 250 251 return (0); 252 } 253 254 int 255 rtentry_delete(struct rtentry *rt, void *w, unsigned int rid) 256 { 257 char dest[INET6_ADDRSTRLEN]; 258 sa_family_t af = rt_key(rt)->sa_family; 259 struct sockaddr_in6 sa_mask; 260 struct sockaddr *mask = rt_plen2mask(rt, &sa_mask); 261 int error; 262 263 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 264 265 if ((error = rtable_delete(0, rt_key(rt), mask, rt)) != 0) { 266 inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest)); 267 errx(1, "can't rm route: %s, %s", dest, strerror(error)); 268 } 269 assert(refcnt_read(&rt->rt_refcnt) == 0); 270 271 return (0); 272 } 273 274 void 275 rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, 276 struct sockaddr *netmask) 277 { 278 uint8_t *cp1 = (uint8_t *)src; 279 uint8_t *cp2 = (uint8_t *)dst; 280 uint8_t *cp3 = (uint8_t *)netmask; 281 uint8_t *cplim = cp2 + *cp3; 282 uint8_t *cplim2 = cp2 + *cp1; 283 284 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 285 cp3 += 2; 286 if (cplim > cplim2) 287 cplim = cplim2; 288 while (cp2 < cplim) 289 *cp2++ = *cp1++ & *cp3++; 290 if (cp2 < cplim2) 291 memset(cp2, 0, (unsigned int)(cplim2 - cp2)); 292 } 293 294 void 295 rtref(struct rtentry *rt) 296 { 297 refcnt_take(&rt->rt_refcnt); 298 } 299 300 void 301 rtfree(struct rtentry *rt) 302 { 303 if (refcnt_rele(&rt->rt_refcnt) == 0) 304 return; 305 } 306 307 void 308 refcnt_init(struct refcnt *r) 309 { 310 r->r_refs = 1; 311 } 312 313 void 314 refcnt_take(struct refcnt *r) 315 { 316 u_int refs; 317 318 refs = ++r->r_refs; 319 assert(refs != 0); 320 } 321 322 int 323 refcnt_rele(struct refcnt *r) 324 { 325 u_int refs; 326 327 refs = --r->r_refs; 328 assert(refs != ~0); 329 if (r->r_refs == 0) 330 return (1); 331 return (0); 332 } 333 334 unsigned int 335 refcnt_read(struct refcnt *r) 336 { 337 return (r->r_refs); 338 } 339 340 void 341 in_prefixlen2mask(struct in_addr *maskp, int plen) 342 { 343 if (plen == 0) 344 maskp->s_addr = 0; 345 else 346 maskp->s_addr = htonl(0xffffffff << (32 - plen)); 347 } 348 349 void 350 in6_prefixlen2mask(struct in6_addr *maskp, int len) 351 { 352 uint8_t maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 353 int bytelen, bitlen, i; 354 355 assert(0 <= len && len <= 128); 356 357 memset(maskp, 0, sizeof(*maskp)); 358 bytelen = len / 8; 359 bitlen = len % 8; 360 for (i = 0; i < bytelen; i++) 361 maskp->s6_addr[i] = 0xff; 362 /* len == 128 is ok because bitlen == 0 then */ 363 if (bitlen) 364 maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 365 } 366 367 struct sockaddr * 368 rt_plentosa(sa_family_t af, int plen, struct sockaddr_in6 *sa_mask) 369 { 370 struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; 371 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; 372 373 assert(plen >= 0 || plen == -1); 374 375 if (plen == -1) 376 return (NULL); 377 378 memset(sa_mask, 0, sizeof(*sa_mask)); 379 380 switch (af) { 381 case AF_INET: 382 sin->sin_family = AF_INET; 383 sin->sin_len = sizeof(struct sockaddr_in); 384 in_prefixlen2mask(&sin->sin_addr, plen); 385 break; 386 case AF_INET6: 387 sin6->sin6_family = AF_INET6; 388 sin6->sin6_len = sizeof(struct sockaddr_in6); 389 in6_prefixlen2mask(&sin6->sin6_addr, plen); 390 break; 391 default: 392 return (NULL); 393 } 394 395 return ((struct sockaddr *)sa_mask); 396 } 397 398 struct sockaddr * 399 rt_plen2mask(struct rtentry *rt, struct sockaddr_in6 *sa_mask) 400 { 401 return (rt_plentosa(rt_key(rt)->sa_family, rt_plen(rt), sa_mask)); 402 } 403 404 405 int 406 inet_net_ptosa(sa_family_t af, const char *buf, struct sockaddr *sa, 407 struct sockaddr *ma) 408 { 409 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 410 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 411 int i, plen; 412 413 switch (af) { 414 case AF_INET: 415 memset(sin, 0, sizeof(*sin)); 416 sin->sin_family = af; 417 sin->sin_len = sizeof(*sin); 418 plen = inet_net_pton(af, buf, &sin->sin_addr, 419 sizeof(sin->sin_addr)); 420 if (plen == -1 || ma == NULL) 421 break; 422 423 sin = (struct sockaddr_in *)ma; 424 memset(sin, 0, sizeof(*sin)); 425 sin->sin_len = sizeof(*sin); 426 sin->sin_family = 0; 427 in_prefixlen2mask(&sin->sin_addr, plen); 428 break; 429 case AF_INET6: 430 memset(sin6, 0, sizeof(*sin6)); 431 sin6->sin6_family = af; 432 sin6->sin6_len = sizeof(*sin6); 433 plen = inet_net_pton(af, buf, &sin6->sin6_addr, 434 sizeof(sin6->sin6_addr)); 435 if (plen == -1 || ma == NULL) 436 break; 437 438 sin6 = (struct sockaddr_in6 *)ma; 439 memset(sin6, 0, sizeof(*sin6)); 440 sin6->sin6_len = sizeof(*sin6); 441 sin6->sin6_family = 0; 442 for (i = 0; i < plen / 8; i++) 443 sin6->sin6_addr.s6_addr[i] = 0xff; 444 i = plen % 8; 445 if (i) 446 sin6->sin6_addr.s6_addr[plen / 8] = 0xff00 >> i; 447 break; 448 default: 449 plen = -1; 450 } 451 452 return (plen); 453 } 454 455 /* 456 * Only compare the address fields, we cannot use memcmp(3) because 457 * the radix tree abuses the first fields of the mask sockaddr for 458 * a different purpose. 459 */ 460 int 461 maskcmp(sa_family_t af, struct sockaddr *sa1, struct sockaddr *sa2) 462 { 463 struct sockaddr_in *sin1, *sin2; 464 struct sockaddr_in6 *sin61, *sin62; 465 int len; 466 467 switch (af) { 468 case AF_INET: 469 sin1 = (struct sockaddr_in *)sa1; 470 sin2 = (struct sockaddr_in *)sa2; 471 len = sizeof(sin1->sin_addr); 472 return memcmp(&sin1->sin_addr, &sin2->sin_addr, len); 473 case AF_INET6: 474 sin61 = (struct sockaddr_in6 *)sa1; 475 sin62 = (struct sockaddr_in6 *)sa2; 476 len = sizeof(sin61->sin6_addr); 477 return memcmp(&sin61->sin6_addr, &sin62->sin6_addr, len); 478 default: 479 return (-1); 480 } 481 } 482 483 char * 484 inet_net_satop(sa_family_t af, struct sockaddr *sa, int plen, char *buf, 485 size_t len) 486 { 487 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 488 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 489 490 switch (af) { 491 case AF_INET: 492 return inet_net_ntop(af, &sin->sin_addr, plen, buf, len); 493 case AF_INET6: 494 return inet_net_ntop(af, &sin6->sin6_addr, plen, buf, len); 495 default: 496 return (NULL); 497 } 498 } 499 500 /* Give some jitter to hash, to avoid synchronization between routers. */ 501 static uint32_t rt_hashjitter; 502 503 /* 504 * Originated from bridge_hash() in if_bridge.c 505 */ 506 #define mix(a, b, c) do { \ 507 a -= b; a -= c; a ^= (c >> 13); \ 508 b -= c; b -= a; b ^= (a << 8); \ 509 c -= a; c -= b; c ^= (b >> 13); \ 510 a -= b; a -= c; a ^= (c >> 12); \ 511 b -= c; b -= a; b ^= (a << 16); \ 512 c -= a; c -= b; c ^= (b >> 5); \ 513 a -= b; a -= c; a ^= (c >> 3); \ 514 b -= c; b -= a; b ^= (a << 10); \ 515 c -= a; c -= b; c ^= (b >> 15); \ 516 } while (0) 517 518 int 519 rt_hash(struct rtentry *rt, const struct sockaddr *dst, uint32_t *src) 520 { 521 uint32_t a, b, c; 522 523 while (rt_hashjitter == 0) 524 rt_hashjitter = arc4random(); 525 526 if (src == NULL) 527 return (-1); 528 529 a = b = 0x9e3779b9; 530 c = rt_hashjitter; 531 532 switch (dst->sa_family) { 533 case AF_INET: 534 { 535 struct sockaddr_in *sin; 536 537 sin = satosin(dst); 538 a += sin->sin_addr.s_addr; 539 b += (src != NULL) ? src[0] : 0; 540 mix(a, b, c); 541 break; 542 } 543 #ifdef INET6 544 case AF_INET6: 545 { 546 struct sockaddr_in6 *sin6; 547 548 sin6 = satosin6(dst); 549 a += sin6->sin6_addr.s6_addr32[0]; 550 b += sin6->sin6_addr.s6_addr32[2]; 551 c += (src != NULL) ? src[0] : 0; 552 mix(a, b, c); 553 a += sin6->sin6_addr.s6_addr32[1]; 554 b += sin6->sin6_addr.s6_addr32[3]; 555 c += (src != NULL) ? src[1] : 0; 556 mix(a, b, c); 557 a += sin6->sin6_addr.s6_addr32[2]; 558 b += sin6->sin6_addr.s6_addr32[1]; 559 c += (src != NULL) ? src[2] : 0; 560 mix(a, b, c); 561 a += sin6->sin6_addr.s6_addr32[3]; 562 b += sin6->sin6_addr.s6_addr32[0]; 563 c += (src != NULL) ? src[3] : 0; 564 mix(a, b, c); 565 break; 566 } 567 #endif /* INET6 */ 568 } 569 570 return (c & 0xffff); 571 } 572 573 void 574 rt_timer_init(void) 575 { 576 } 577