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