xref: /openbsd-src/regress/sys/net/rtable/util.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
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 
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   .dom_ifattach		= NULL,
84   .dom_ifdetach		= NULL,
85 };
86 
87 struct 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 
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
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 
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  */
144 void
145 route_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  */
187 void
188 route_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 
210 int
211 do_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 
234 int
235 rtentry_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 
246 int
247 rtentry_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 
265 void
266 rt_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 
285 void
286 rtref(struct rtentry *rt)
287 {
288 	rt->rt_refcnt.r_refs++;
289 }
290 
291 void
292 rtfree(struct rtentry *rt)
293 {
294 	assert(--(rt->rt_refcnt.r_refs) >= 0);
295 }
296 
297 void
298 in_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 
306 void
307 in6_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 
324 struct sockaddr *
325 rt_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 
355 struct sockaddr *
356 rt_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 
362 int
363 inet_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  */
417 int
418 maskcmp(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 
440 char *
441 inet_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. */
458 static 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 
475 int
476 rt_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 
530 void
531 rt_timer_init(void)
532 {
533 }
534