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