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