GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/util.c Lines: 0 261 0.0 %
Date: 2016-12-06 Branches: 0 229 0.0 %

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