xref: /openbsd/regress/sys/net/rtable/util.c (revision 6822f9c8)
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