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