xref: /openbsd-src/regress/sys/net/rtable/util.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: util.c,v 1.5 2016/03/24 07:03:30 mpi 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 #include "srp_compat.h"
20 
21 #include <sys/socket.h>
22 #include <sys/domain.h>
23 #include <sys/queue.h>
24 #include <sys/srp.h>
25 
26 #include <net/rtable.h>
27 #include <net/route.h>
28 
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 
32 #include <assert.h>
33 #include <err.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "util.h"
40 
41 struct sockaddr *rt_plen2mask(struct rtentry *, struct sockaddr_in6 *);
42 
43 struct domain inetdomain = {
44 	AF_INET, "inet", NULL, NULL, NULL, NULL, NULL,
45 	sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr),
46 	32,
47 };
48 
49 struct domain inet6domain = {
50 	AF_INET6, "inet6", NULL, NULL, NULL, NULL, NULL,
51 	sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr),
52 	128,
53 };
54 
55 struct domain *domains[] = { &inetdomain, &inet6domain, NULL };
56 
57 /*
58  * Insert a route from a string containing a destination: "192.168.1/24"
59  */
60 void
61 route_insert(unsigned int rid, sa_family_t af, char *string)
62 {
63 	struct sockaddr_storage	 ss, ms;
64 	struct sockaddr		*ndst, *dst = (struct sockaddr *)&ss;
65 	struct sockaddr		*mask = (struct sockaddr *)&ms;
66 	struct rtentry		*rt, *nrt;
67 	char			 ip[INET6_ADDRSTRLEN];
68 	int			 plen, error;
69 
70 	rt = calloc(1, sizeof(*rt));
71 	if (rt == NULL)
72 		errx(1, "out of memory");
73 
74 	plen = inet_net_ptosa(af, string, dst, mask);
75 	if (plen == -1)
76 		err(1, "wrong line: %s", string);
77 
78 	/* Normalize sockaddr a la rtrequest1(9) */
79 	ndst = malloc(dst->sa_len);
80 	if (ndst == NULL)
81 		errx(1, "out of memory");
82 	rt_maskedcopy(dst, ndst, mask);
83 
84 	if ((error = rtable_insert(rid, ndst, mask, NULL, 0, rt)) != 0) {
85 		inet_net_satop(af, rt_key(rt), plen, ip, sizeof(ip));
86 		errx(1, "can't add route: %s, %s\n", ip, strerror(error));
87 	}
88 	nrt = rtable_lookup(rid, dst, mask, NULL, RTP_ANY);
89 	if (nrt != rt) {
90 		inet_net_satop(af, rt_key(rt), plen, ip, sizeof(ip));
91 		errx(1, "added route not found: %s\n", ip);
92 	}
93 }
94 
95 /*
96  * Delete a route from a string containing a destination: "192.168.1/24"
97  */
98 void
99 route_delete(unsigned int rid, sa_family_t af, char *string)
100 {
101 	struct sockaddr_storage	 ss, ms;
102 	struct sockaddr		*dst = (struct sockaddr *)&ss;
103 	struct sockaddr		*mask = (struct sockaddr *)&ms;
104 	struct rtentry		*rt, *nrt;
105 	char			 ip[INET6_ADDRSTRLEN];
106 	int			 plen, error;
107 
108 	plen = inet_net_ptosa(af, string, dst, mask);
109 	if (plen == -1)
110 		err(1, "wrong line: %s", string);
111 
112 	rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY);
113 	if (rt == NULL) {
114 		inet_net_satop(af, dst, plen, ip, sizeof(ip));
115 		errx(1, "can't find route: %s\n", ip);
116 	}
117 
118 	assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0);
119 	assert(rt_plen(rt) == rtable_satoplen(af, mask));
120 
121 	if ((error = rtable_delete(0, dst, mask, rt)) != 0) {
122 		inet_net_satop(af, dst, plen, ip, sizeof(ip));
123 		errx(1, "can't rm route: %s, %s\n", ip, strerror(error));
124 	}
125 
126 	nrt = rtable_lookup(0, dst, mask, NULL, RTP_ANY);
127 	if (nrt != NULL) {
128 		char ip0[INET6_ADDRSTRLEN];
129 		inet_net_satop(af, rt_key(nrt), plen, ip, sizeof(ip));
130 		inet_net_satop(af, rt_key(rt), plen, ip0, sizeof(ip0));
131 		errx(1, "found: %s after deleting: %s", ip, ip0);
132 	}
133 
134 	free(rt_key(rt));
135 	free(rt);
136 }
137 
138 /*
139  * Lookup a route from a string containing a destination: "192.168.1/24"
140  */
141 void
142 route_lookup(unsigned int rid, sa_family_t af, char *string)
143 {
144 	struct sockaddr_storage	 ss, ms;
145 	struct sockaddr		*dst = (struct sockaddr *)&ss;
146 	struct sockaddr		*mask = (struct sockaddr *)&ms;
147 	struct rtentry		*rt;
148 	char			 ip[INET6_ADDRSTRLEN];
149 	int			 plen;
150 
151 	plen = inet_net_ptosa(af, string, dst, mask);
152 	if (plen == -1)
153 		err(1, "wrong line: %s", string);
154 
155 	rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY);
156 	if (rt == NULL) {
157 		inet_net_satop(af, dst, plen, ip, sizeof(ip));
158 		errx(1, "%s not found\n", ip);
159 	}
160 	assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0);
161 	assert(rt_plen(rt) == rtable_satoplen(af, mask));
162 }
163 
164 int
165 do_from_file(unsigned int rid, sa_family_t af, char *filename,
166     void (*func)(unsigned int, sa_family_t, char *))
167 {
168 	FILE			*fp;
169 	char			*buf;
170 	size_t			 len;
171 	int			 lines = 0;
172 
173 	if ((fp = fopen(filename, "r")) == NULL)
174 		errx(1, "No such file: %s\n", filename);
175 
176 	while ((buf = fgetln(fp, &len)) != NULL) {
177 		if (buf[len - 1] == '\n')
178 			buf[len - 1] = '\0';
179 
180 		(*func)(rid, af, buf);
181 		lines++;
182 	}
183 	fclose(fp);
184 
185 	return (lines);
186 }
187 
188 int
189 rtentry_dump(struct rtentry *rt, void *w, unsigned int rid)
190 {
191 	char			 dest[INET6_ADDRSTRLEN];
192 	sa_family_t		 af = rt_key(rt)->sa_family;
193 
194 	inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest));
195 	printf("%s\n", dest);
196 
197 	return (0);
198 }
199 
200 int
201 rtentry_delete(struct rtentry *rt, void *w, unsigned int rid)
202 {
203 	char			 dest[INET6_ADDRSTRLEN];
204 	sa_family_t		 af = rt_key(rt)->sa_family;
205 	struct sockaddr_in6	 sa_mask;
206 	struct sockaddr		*mask = rt_plen2mask(rt, &sa_mask);
207 	int			 error;
208 
209 	assert(rt_plen(rt) == rtable_satoplen(af, mask));
210 
211 	if ((error = rtable_delete(0, rt_key(rt), mask, rt)) != 0) {
212 		inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest));
213 		errx(1, "can't rm route: %s, %s\n", dest, strerror(error));
214 	}
215 
216 	return (0);
217 }
218 
219 void
220 rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
221     struct sockaddr *netmask)
222 {
223 	uint8_t	*cp1 = (uint8_t *)src;
224 	uint8_t	*cp2 = (uint8_t *)dst;
225 	uint8_t	*cp3 = (uint8_t *)netmask;
226 	uint8_t	*cplim = cp2 + *cp3;
227 	uint8_t	*cplim2 = cp2 + *cp1;
228 
229 	*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
230 	cp3 += 2;
231 	if (cplim > cplim2)
232 		cplim = cplim2;
233 	while (cp2 < cplim)
234 		*cp2++ = *cp1++ & *cp3++;
235 	if (cp2 < cplim2)
236 		memset(cp2, 0, (unsigned int)(cplim2 - cp2));
237 }
238 
239 void
240 in_prefixlen2mask(struct in_addr *maskp, int plen)
241 {
242 	if (plen == 0)
243 		maskp->s_addr = 0;
244 	else
245 		maskp->s_addr = htonl(0xffffffff << (32 - plen));
246 }
247 
248 void
249 in6_prefixlen2mask(struct in6_addr *maskp, int len)
250 {
251 	uint8_t maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
252 	int bytelen, bitlen, i;
253 
254 	assert(0 <= len && len <= 128);
255 
256 	memset(maskp, 0, sizeof(*maskp));
257 	bytelen = len / 8;
258 	bitlen = len % 8;
259 	for (i = 0; i < bytelen; i++)
260 		maskp->s6_addr[i] = 0xff;
261 	/* len == 128 is ok because bitlen == 0 then */
262 	if (bitlen)
263 		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
264 }
265 
266 struct sockaddr *
267 rt_plentosa(sa_family_t af, int plen, struct sockaddr_in6 *sa_mask)
268 {
269 	struct sockaddr_in	*sin = (struct sockaddr_in *)sa_mask;
270 	struct sockaddr_in6	*sin6 = (struct sockaddr_in6 *)sa_mask;
271 
272 	assert(plen >= 0 || plen == -1);
273 
274 	if (plen == -1)
275 		return (NULL);
276 
277 	memset(sa_mask, 0, sizeof(*sa_mask));
278 
279 	switch (af) {
280 	case AF_INET:
281 		sin->sin_family = AF_INET;
282 		sin->sin_len = sizeof(struct sockaddr_in);
283 		in_prefixlen2mask(&sin->sin_addr, plen);
284 		break;
285 	case AF_INET6:
286 		sin6->sin6_family = AF_INET6;
287 		sin6->sin6_len = sizeof(struct sockaddr_in6);
288 		in6_prefixlen2mask(&sin6->sin6_addr, plen);
289 		break;
290 	default:
291 		return (NULL);
292 	}
293 
294 	return ((struct sockaddr *)sa_mask);
295 }
296 
297 struct sockaddr *
298 rt_plen2mask(struct rtentry *rt, struct sockaddr_in6 *sa_mask)
299 {
300 #ifndef ART
301 	return (rt_mask(rt));
302 #else
303 	return (rt_plentosa(rt_key(rt)->sa_family, rt_plen(rt), sa_mask));
304 #endif /* ART */
305 }
306 
307 
308 int
309 inet_net_ptosa(sa_family_t af, const char *buf, struct sockaddr *sa,
310     struct sockaddr *ma)
311 {
312 	struct sockaddr_in *sin = (struct sockaddr_in *)sa;
313 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
314 	int i, plen;
315 
316 	switch (af) {
317 	case AF_INET:
318 		memset(sin, 0, sizeof(*sin));
319 		sin->sin_family = af;
320 		sin->sin_len = sizeof(*sin);
321 		plen = inet_net_pton(af, buf, &sin->sin_addr,
322 		    sizeof(sin->sin_addr));
323 		if (plen == -1 || ma == NULL)
324 			break;
325 
326 		sin = (struct sockaddr_in *)ma;
327 		memset(sin, 0, sizeof(*sin));
328 		sin->sin_len = sizeof(*sin);
329 		sin->sin_family = 0;
330 		in_prefixlen2mask(&sin->sin_addr, plen);
331 		break;
332 	case AF_INET6:
333 		memset(sin6, 0, sizeof(*sin6));
334 		sin6->sin6_family = af;
335 		sin6->sin6_len = sizeof(*sin6);
336 		plen = inet_net_pton(af, buf, &sin6->sin6_addr,
337 		    sizeof(sin6->sin6_addr));
338 		if (plen == -1 || ma == NULL)
339 			break;
340 
341 		sin6 = (struct sockaddr_in6 *)ma;
342 		memset(sin6, 0, sizeof(*sin6));
343 		sin6->sin6_len = sizeof(*sin6);
344 		sin6->sin6_family = 0;
345 		for (i = 0; i < plen / 8; i++)
346 			sin6->sin6_addr.s6_addr[i] = 0xff;
347 		i = plen % 8;
348 		if (i)
349 			sin6->sin6_addr.s6_addr[plen / 8] = 0xff00 >> i;
350 		break;
351 	default:
352 		plen = -1;
353 	}
354 
355 	return (plen);
356 }
357 
358 /*
359  * Only compare the address fields, we cannot use memcmp(3) because
360  * the radix tree abuses the first fields of the mask sockaddr for
361  * a different purpose.
362  */
363 int
364 maskcmp(sa_family_t af, struct sockaddr *sa1, struct sockaddr *sa2)
365 {
366 	struct sockaddr_in *sin1, *sin2;
367 	struct sockaddr_in6 *sin61, *sin62;
368 	int len;
369 
370 	switch (af) {
371 	case AF_INET:
372 		sin1 = (struct sockaddr_in *)sa1;
373 		sin2 = (struct sockaddr_in *)sa2;
374 		len = sizeof(sin1->sin_addr);
375 		return memcmp(&sin1->sin_addr, &sin2->sin_addr, len);
376 	case AF_INET6:
377 		sin61 = (struct sockaddr_in6 *)sa1;
378 		sin62 = (struct sockaddr_in6 *)sa2;
379 		len = sizeof(sin61->sin6_addr);
380 		return memcmp(&sin61->sin6_addr, &sin62->sin6_addr, len);
381 	default:
382 		return (-1);
383 	}
384 }
385 
386 char *
387 inet_net_satop(sa_family_t af, struct sockaddr *sa, int plen, char *buf,
388     size_t len)
389 {
390 	struct sockaddr_in *sin = (struct sockaddr_in *)sa;
391 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
392 
393 	switch (af) {
394 	case AF_INET:
395 		return inet_net_ntop(af, &sin->sin_addr, plen, buf, len);
396 	case AF_INET6:
397 		return inet_net_ntop(af, &sin6->sin6_addr, plen, buf, len);
398 	default:
399 		return (NULL);
400 	}
401 }
402