xref: /openbsd-src/usr.sbin/bgpd/util.c (revision d59bb9942320b767f2a19aaa7690c8c6e30b724c)
1 /*	$OpenBSD: util.c,v 1.24 2017/01/24 04:22:42 benno Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <vis.h>
28 
29 #include "bgpd.h"
30 #include "rde.h"
31 #include "log.h"
32 
33 const char	*aspath_delim(u_int8_t, int);
34 
35 const char *
36 log_addr(const struct bgpd_addr *addr)
37 {
38 	static char	buf[48];
39 	char		tbuf[16];
40 
41 	switch (addr->aid) {
42 	case AID_INET:
43 	case AID_INET6:
44 		if (inet_ntop(aid2af(addr->aid), &addr->ba, buf,
45 		    sizeof(buf)) == NULL)
46 			return ("?");
47 		return (buf);
48 	case AID_VPN_IPv4:
49 		if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf,
50 		    sizeof(tbuf)) == NULL)
51 			return ("?");
52 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
53 		   tbuf);
54 		return (buf);
55 	}
56 	return ("???");
57 }
58 
59 const char *
60 log_in6addr(const struct in6_addr *addr)
61 {
62 	struct sockaddr_in6	sa_in6;
63 	u_int16_t		tmp16;
64 
65 	bzero(&sa_in6, sizeof(sa_in6));
66 	sa_in6.sin6_len = sizeof(sa_in6);
67 	sa_in6.sin6_family = AF_INET6;
68 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
69 
70 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
71 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
72 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
73 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
74 		sa_in6.sin6_scope_id = ntohs(tmp16);
75 		sa_in6.sin6_addr.s6_addr[2] = 0;
76 		sa_in6.sin6_addr.s6_addr[3] = 0;
77 	}
78 
79 	return (log_sockaddr((struct sockaddr *)&sa_in6));
80 }
81 
82 const char *
83 log_sockaddr(struct sockaddr *sa)
84 {
85 	static char	buf[NI_MAXHOST];
86 
87 	if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
88 	    NI_NUMERICHOST))
89 		return ("(unknown)");
90 	else
91 		return (buf);
92 }
93 
94 const char *
95 log_as(u_int32_t as)
96 {
97 	static char	buf[11];	/* "4294967294\0" */
98 
99 	if (snprintf(buf, sizeof(buf), "%u", as) == -1)
100 		return ("?");
101 
102 	return (buf);
103 }
104 
105 const char *
106 log_rd(u_int64_t rd)
107 {
108 	static char	buf[32];
109 	struct in_addr	addr;
110 	u_int32_t	u32;
111 	u_int16_t	u16;
112 
113 	rd = betoh64(rd);
114 	switch (rd >> 48) {
115 	case EXT_COMMUNITY_TWO_AS:
116 		u32 = rd & 0xffffffff;
117 		u16 = (rd >> 32) & 0xffff;
118 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
119 		break;
120 	case EXT_COMMUNITY_FOUR_AS:
121 		u32 = (rd >> 16) & 0xffffffff;
122 		u16 = rd & 0xffff;
123 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
124 		break;
125 	case EXT_COMMUNITY_IPV4:
126 		u32 = (rd >> 16) & 0xffffffff;
127 		u16 = rd & 0xffff;
128 		addr.s_addr = htonl(u32);
129 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
130 		break;
131 	default:
132 		return ("rd ?");
133 	}
134 	return (buf);
135 }
136 
137 /* NOTE: this function does not check if the type/subtype combo is
138  * actually valid. */
139 const char *
140 log_ext_subtype(u_int8_t subtype)
141 {
142 	static char etype[6];
143 
144 	switch (subtype) {
145 	case EXT_COMMUNITY_ROUTE_TGT:
146 		return ("rt");	/* route target */
147 	case EXT_COMMUNITY_ROUTE_ORIG:
148 		return ("soo");	/* source of origin */
149 	case EXT_COMMUNITY_OSPF_DOM_ID:
150 		return ("odi");	/* ospf domain id */
151 	case EXT_COMMUNITY_OSPF_RTR_TYPE:
152 		return ("ort");	/* ospf route type */
153 	case EXT_COMMUNITY_OSPF_RTR_ID:
154 		return ("ori");	/* ospf router id */
155 	case EXT_COMMUNITY_BGP_COLLECT:
156 		return ("bdc");	/* bgp data collection */
157 	default:
158 		snprintf(etype, sizeof(etype), "[%u]", subtype);
159 		return (etype);
160 	}
161 }
162 
163 const char *
164 log_shutcomm(const char *communication) {
165 	static char buf[(SHUT_COMM_LEN - 1) * 4 + 1];
166 
167 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
168 
169 	return buf;
170 }
171 
172 const char *
173 aspath_delim(u_int8_t seg_type, int closing)
174 {
175 	static char db[8];
176 
177 	switch (seg_type) {
178 	case AS_SET:
179 		if (!closing)
180 			return ("{ ");
181 		else
182 			return (" }");
183 	case AS_SEQUENCE:
184 		return ("");
185 	case AS_CONFED_SEQUENCE:
186 		if (!closing)
187 			return ("( ");
188 		else
189 			return (" )");
190 	case AS_CONFED_SET:
191 		if (!closing)
192 			return ("[ ");
193 		else
194 			return (" ]");
195 	default:
196 		if (!closing)
197 			snprintf(db, sizeof(db), "!%u ", seg_type);
198 		else
199 			snprintf(db, sizeof(db), " !%u", seg_type);
200 		return (db);
201 	}
202 }
203 
204 int
205 aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
206 {
207 #define UPDATE()				\
208 	do {					\
209 		if (r == -1)			\
210 			return (-1);		\
211 		total_size += r;		\
212 		if ((unsigned int)r < size) {	\
213 			size -= r;		\
214 			buf += r;		\
215 		} else {			\
216 			buf += size;		\
217 			size = 0;		\
218 		}				\
219 	} while (0)
220 	u_int8_t	*seg;
221 	int		 r, total_size;
222 	u_int16_t	 seg_size;
223 	u_int8_t	 i, seg_type, seg_len;
224 
225 	total_size = 0;
226 	seg = data;
227 	for (; len > 0; len -= seg_size, seg += seg_size) {
228 		seg_type = seg[0];
229 		seg_len = seg[1];
230 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
231 
232 		r = snprintf(buf, size, "%s%s",
233 		    total_size != 0 ? " " : "",
234 		    aspath_delim(seg_type, 0));
235 		UPDATE();
236 
237 		for (i = 0; i < seg_len; i++) {
238 			r = snprintf(buf, size, "%s",
239 			    log_as(aspath_extract(seg, i)));
240 			UPDATE();
241 			if (i + 1 < seg_len) {
242 				r = snprintf(buf, size, " ");
243 				UPDATE();
244 			}
245 		}
246 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
247 		UPDATE();
248 	}
249 	/* ensure that we have a valid C-string especially for empty as path */
250 	if (size > 0)
251 		*buf = '\0';
252 
253 	return (total_size);
254 #undef UPDATE
255 }
256 
257 int
258 aspath_asprint(char **ret, void *data, u_int16_t len)
259 {
260 	size_t	slen;
261 	int	plen;
262 
263 	slen = aspath_strlen(data, len) + 1;
264 	*ret = malloc(slen);
265 	if (*ret == NULL)
266 		return (-1);
267 
268 	plen = aspath_snprint(*ret, slen, data, len);
269 	if (plen == -1) {
270 		free(*ret);
271 		*ret = NULL;
272 		return (-1);
273 	}
274 
275 	return (0);
276 }
277 
278 size_t
279 aspath_strlen(void *data, u_int16_t len)
280 {
281 	u_int8_t	*seg;
282 	int		 total_size;
283 	u_int32_t	 as;
284 	u_int16_t	 seg_size;
285 	u_int8_t	 i, seg_type, seg_len;
286 
287 	total_size = 0;
288 	seg = data;
289 	for (; len > 0; len -= seg_size, seg += seg_size) {
290 		seg_type = seg[0];
291 		seg_len = seg[1];
292 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
293 
294 		if (seg_type == AS_SET)
295 			if (total_size != 0)
296 				total_size += 3;
297 			else
298 				total_size += 2;
299 		else if (total_size != 0)
300 			total_size += 1;
301 
302 		for (i = 0; i < seg_len; i++) {
303 			as = aspath_extract(seg, i);
304 
305 			do {
306 				total_size++;
307 			} while ((as = as / 10) != 0);
308 
309 			if (i + 1 < seg_len)
310 				total_size += 1;
311 		}
312 
313 		if (seg_type == AS_SET)
314 			total_size += 2;
315 	}
316 	return (total_size);
317 }
318 
319 /* we need to be able to search more than one as */
320 int
321 aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
322 {
323 	u_int8_t	*seg;
324 	int		 final;
325 	u_int16_t	 seg_size;
326 	u_int8_t	 i, seg_len;
327 	u_int32_t	 as;
328 
329 	if (f->type == AS_EMPTY) {
330 		if (len == 0)
331 			return (1);
332 		else
333 			return (0);
334 	}
335 
336 	seg = data;
337 	for (; len > 0; len -= seg_size, seg += seg_size) {
338 		seg_len = seg[1];
339 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
340 
341 		final = (len == seg_size);
342 
343 		/* just check the first (leftmost) AS */
344 		if (f->type == AS_PEER) {
345 			as = aspath_extract(seg, 0);
346 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
347 				return (1);
348 			else
349 				return (0);
350 		}
351 		/* just check the final (rightmost) AS */
352 		if (f->type == AS_SOURCE) {
353 			/* not yet in the final segment */
354 			if (!final)
355 				continue;
356 			as = aspath_extract(seg, seg_len - 1);
357 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
358 				return (1);
359 			else
360 				return (0);
361 		}
362 		/* AS_TRANSIT or AS_ALL */
363 		for (i = 0; i < seg_len; i++) {
364 			/*
365 			 * the source (rightmost) AS is excluded from
366 			 * AS_TRANSIT matches.
367 			 */
368 			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
369 				return (0);
370 			as = aspath_extract(seg, i);
371 			if (as_compare(f->op, as, match, f->as_min, f->as_max))
372 				return (1);
373 		}
374 	}
375 	return (0);
376 }
377 
378 int
379 as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min,
380     u_int32_t as_max)
381 {
382 	if ((op == OP_NONE || op == OP_EQ) && as == match)
383 		return (1);
384 	else if (op == OP_NE && as != match)
385 		return (1);
386 	else if (op == OP_RANGE && as >= as_min && as <= as_max)
387 		return (1);
388 	else if (op == OP_XRANGE && as > as_min && as < as_max)
389 		return (1);
390 	return (0);
391 }
392 
393 /*
394  * Extract the asnum out of the as segment at the specified position.
395  * Direct access is not possible because of non-aligned reads.
396  * ATTENTION: no bounds checks are done.
397  */
398 u_int32_t
399 aspath_extract(const void *seg, int pos)
400 {
401 	const u_char	*ptr = seg;
402 	u_int32_t	 as;
403 
404 	ptr += 2 + sizeof(u_int32_t) * pos;
405 	memcpy(&as, ptr, sizeof(u_int32_t));
406 	return (ntohl(as));
407 }
408 
409 /*
410  * This function will have undefined behaviour if the passed in prefixlen is
411  * to large for the respective bgpd_addr address family.
412  */
413 int
414 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
415     int prefixlen)
416 {
417 	in_addr_t	mask, aa, ba;
418 	int		i;
419 	u_int8_t	m;
420 
421 	if (a->aid != b->aid)
422 		return (a->aid - b->aid);
423 
424 	switch (a->aid) {
425 	case AID_INET:
426 		if (prefixlen == 0)
427 			return (0);
428 		if (prefixlen > 32)
429 			return (-1);
430 		mask = htonl(prefixlen2mask(prefixlen));
431 		aa = ntohl(a->v4.s_addr & mask);
432 		ba = ntohl(b->v4.s_addr & mask);
433 		if (aa != ba)
434 			return (aa - ba);
435 		return (0);
436 	case AID_INET6:
437 		if (prefixlen == 0)
438 			return (0);
439 		if (prefixlen > 128)
440 			return (-1);
441 		for (i = 0; i < prefixlen / 8; i++)
442 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
443 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
444 		i = prefixlen % 8;
445 		if (i) {
446 			m = 0xff00 >> i;
447 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
448 			    (b->v6.s6_addr[prefixlen / 8] & m))
449 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
450 				    (b->v6.s6_addr[prefixlen / 8] & m));
451 		}
452 		return (0);
453 	case AID_VPN_IPv4:
454 		if (prefixlen > 32)
455 			return (-1);
456 		if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
457 			return (1);
458 		if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
459 			return (-1);
460 		mask = htonl(prefixlen2mask(prefixlen));
461 		aa = ntohl(a->vpn4.addr.s_addr & mask);
462 		ba = ntohl(b->vpn4.addr.s_addr & mask);
463 		if (aa != ba)
464 			return (aa - ba);
465 		if (a->vpn4.labellen > b->vpn4.labellen)
466 			return (1);
467 		if (a->vpn4.labellen < b->vpn4.labellen)
468 			return (-1);
469 		return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
470 		    a->vpn4.labellen));
471 	}
472 	return (-1);
473 }
474 
475 in_addr_t
476 prefixlen2mask(u_int8_t prefixlen)
477 {
478 	if (prefixlen == 0)
479 		return (0);
480 
481 	return (0xffffffff << (32 - prefixlen));
482 }
483 
484 void
485 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
486 {
487 	struct in6_addr	mask;
488 	int		i;
489 
490 	bzero(&mask, sizeof(mask));
491 	for (i = 0; i < prefixlen / 8; i++)
492 		mask.s6_addr[i] = 0xff;
493 	i = prefixlen % 8;
494 	if (i)
495 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
496 
497 	for (i = 0; i < 16; i++)
498 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
499 }
500 
501 /* address family translation functions */
502 const struct aid aid_vals[AID_MAX] = AID_VALS;
503 
504 const char *
505 aid2str(u_int8_t aid)
506 {
507 	if (aid < AID_MAX)
508 		return (aid_vals[aid].name);
509 	return ("unknown AID");
510 }
511 
512 int
513 aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
514 {
515 	if (aid < AID_MAX) {
516 		*afi = aid_vals[aid].afi;
517 		*safi = aid_vals[aid].safi;
518 		return (0);
519 	}
520 	return (-1);
521 }
522 
523 int
524 afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
525 {
526 	u_int8_t i;
527 
528 	for (i = 0; i < AID_MAX; i++)
529 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
530 			*aid = i;
531 			return (0);
532 		}
533 
534 	return (-1);
535 }
536 
537 sa_family_t
538 aid2af(u_int8_t aid)
539 {
540 	if (aid < AID_MAX)
541 		return (aid_vals[aid].af);
542 	return (AF_UNSPEC);
543 }
544 
545 int
546 af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
547 {
548 	u_int8_t i;
549 
550 	if (safi == 0) /* default to unicast subclass */
551 		safi = SAFI_UNICAST;
552 
553 	for (i = 0; i < AID_MAX; i++)
554 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
555 			*aid = i;
556 			return (0);
557 		}
558 
559 	return (-1);
560 }
561 
562 struct sockaddr *
563 addr2sa(struct bgpd_addr *addr, u_int16_t port)
564 {
565 	static struct sockaddr_storage	 ss;
566 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
567 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
568 
569 	if (addr->aid == AID_UNSPEC)
570 		return (NULL);
571 
572 	bzero(&ss, sizeof(ss));
573 	switch (addr->aid) {
574 	case AID_INET:
575 		sa_in->sin_family = AF_INET;
576 		sa_in->sin_len = sizeof(struct sockaddr_in);
577 		sa_in->sin_addr.s_addr = addr->v4.s_addr;
578 		sa_in->sin_port = htons(port);
579 		break;
580 	case AID_INET6:
581 		sa_in6->sin6_family = AF_INET6;
582 		sa_in6->sin6_len = sizeof(struct sockaddr_in6);
583 		memcpy(&sa_in6->sin6_addr, &addr->v6,
584 		    sizeof(sa_in6->sin6_addr));
585 		sa_in6->sin6_port = htons(port);
586 		sa_in6->sin6_scope_id = addr->scope_id;
587 		break;
588 	}
589 
590 	return ((struct sockaddr *)&ss);
591 }
592 
593 void
594 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr)
595 {
596 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
597 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
598 
599 	bzero(addr, sizeof(*addr));
600 	switch (sa->sa_family) {
601 	case AF_INET:
602 		addr->aid = AID_INET;
603 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
604 		break;
605 	case AF_INET6:
606 		addr->aid = AID_INET6;
607 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
608 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
609 		break;
610 	}
611 }
612