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
route_insert(unsigned int rid,sa_family_t af,char * string)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
route_delete(unsigned int rid,sa_family_t af,char * string)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
route_lookup(unsigned int rid,sa_family_t af,char * string)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
do_from_file(unsigned int rid,sa_family_t af,char * filename,void (* func)(unsigned int,sa_family_t,char *))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
rtentry_dump(struct rtentry * rt,void * w,unsigned int rid)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
rtentry_delete(struct rtentry * rt,void * w,unsigned int rid)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
rt_maskedcopy(struct sockaddr * src,struct sockaddr * dst,struct sockaddr * netmask)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
rtref(struct rtentry * rt)295 rtref(struct rtentry *rt)
296 {
297 refcnt_take(&rt->rt_refcnt);
298 }
299
300 void
rtfree(struct rtentry * rt)301 rtfree(struct rtentry *rt)
302 {
303 if (refcnt_rele(&rt->rt_refcnt) == 0)
304 return;
305 }
306
307 void
refcnt_init(struct refcnt * r)308 refcnt_init(struct refcnt *r)
309 {
310 r->r_refs = 1;
311 }
312
313 void
refcnt_take(struct refcnt * r)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
refcnt_rele(struct refcnt * r)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
refcnt_read(struct refcnt * r)335 refcnt_read(struct refcnt *r)
336 {
337 return (r->r_refs);
338 }
339
340 void
in_prefixlen2mask(struct in_addr * maskp,int plen)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
in6_prefixlen2mask(struct in6_addr * maskp,int len)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 *
rt_plentosa(sa_family_t af,int plen,struct sockaddr_in6 * sa_mask)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 *
rt_plen2mask(struct rtentry * rt,struct sockaddr_in6 * sa_mask)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
inet_net_ptosa(sa_family_t af,const char * buf,struct sockaddr * sa,struct sockaddr * ma)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
maskcmp(sa_family_t af,struct sockaddr * sa1,struct sockaddr * sa2)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 *
inet_net_satop(sa_family_t af,struct sockaddr * sa,int plen,char * buf,size_t len)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
rt_hash(struct rtentry * rt,const struct sockaddr * dst,uint32_t * src)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
rt_timer_init(void)574 rt_timer_init(void)
575 {
576 }
577