GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/../bgpd/util.c Lines: 0 264 0.0 %
Date: 2017-11-13 Branches: 0 207 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: util.c,v 1.25 2017/05/31 10:44:00 claudio 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_TRANS_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_TRANS_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_TRANS_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
const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
138
139
/* NOTE: this function does not check if the type/subtype combo is
140
 * actually valid. */
141
const char *
142
log_ext_subtype(u_int8_t type, u_int8_t subtype)
143
{
144
	static char etype[6];
145
	const struct ext_comm_pairs *cp;
146
147
	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
148
		if (type == cp->type && subtype == cp->subtype)
149
			return (cp->subname);
150
	}
151
	snprintf(etype, sizeof(etype), "[%u]", subtype);
152
	return (etype);
153
}
154
155
const char *
156
log_shutcomm(const char *communication) {
157
	static char buf[(SHUT_COMM_LEN - 1) * 4 + 1];
158
159
	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
160
161
	return buf;
162
}
163
164
const char *
165
aspath_delim(u_int8_t seg_type, int closing)
166
{
167
	static char db[8];
168
169
	switch (seg_type) {
170
	case AS_SET:
171
		if (!closing)
172
			return ("{ ");
173
		else
174
			return (" }");
175
	case AS_SEQUENCE:
176
		return ("");
177
	case AS_CONFED_SEQUENCE:
178
		if (!closing)
179
			return ("( ");
180
		else
181
			return (" )");
182
	case AS_CONFED_SET:
183
		if (!closing)
184
			return ("[ ");
185
		else
186
			return (" ]");
187
	default:
188
		if (!closing)
189
			snprintf(db, sizeof(db), "!%u ", seg_type);
190
		else
191
			snprintf(db, sizeof(db), " !%u", seg_type);
192
		return (db);
193
	}
194
}
195
196
int
197
aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
198
{
199
#define UPDATE()				\
200
	do {					\
201
		if (r == -1)			\
202
			return (-1);		\
203
		total_size += r;		\
204
		if ((unsigned int)r < size) {	\
205
			size -= r;		\
206
			buf += r;		\
207
		} else {			\
208
			buf += size;		\
209
			size = 0;		\
210
		}				\
211
	} while (0)
212
	u_int8_t	*seg;
213
	int		 r, total_size;
214
	u_int16_t	 seg_size;
215
	u_int8_t	 i, seg_type, seg_len;
216
217
	total_size = 0;
218
	seg = data;
219
	for (; len > 0; len -= seg_size, seg += seg_size) {
220
		seg_type = seg[0];
221
		seg_len = seg[1];
222
		seg_size = 2 + sizeof(u_int32_t) * seg_len;
223
224
		r = snprintf(buf, size, "%s%s",
225
		    total_size != 0 ? " " : "",
226
		    aspath_delim(seg_type, 0));
227
		UPDATE();
228
229
		for (i = 0; i < seg_len; i++) {
230
			r = snprintf(buf, size, "%s",
231
			    log_as(aspath_extract(seg, i)));
232
			UPDATE();
233
			if (i + 1 < seg_len) {
234
				r = snprintf(buf, size, " ");
235
				UPDATE();
236
			}
237
		}
238
		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
239
		UPDATE();
240
	}
241
	/* ensure that we have a valid C-string especially for empty as path */
242
	if (size > 0)
243
		*buf = '\0';
244
245
	return (total_size);
246
#undef UPDATE
247
}
248
249
int
250
aspath_asprint(char **ret, void *data, u_int16_t len)
251
{
252
	size_t	slen;
253
	int	plen;
254
255
	slen = aspath_strlen(data, len) + 1;
256
	*ret = malloc(slen);
257
	if (*ret == NULL)
258
		return (-1);
259
260
	plen = aspath_snprint(*ret, slen, data, len);
261
	if (plen == -1) {
262
		free(*ret);
263
		*ret = NULL;
264
		return (-1);
265
	}
266
267
	return (0);
268
}
269
270
size_t
271
aspath_strlen(void *data, u_int16_t len)
272
{
273
	u_int8_t	*seg;
274
	int		 total_size;
275
	u_int32_t	 as;
276
	u_int16_t	 seg_size;
277
	u_int8_t	 i, seg_type, seg_len;
278
279
	total_size = 0;
280
	seg = data;
281
	for (; len > 0; len -= seg_size, seg += seg_size) {
282
		seg_type = seg[0];
283
		seg_len = seg[1];
284
		seg_size = 2 + sizeof(u_int32_t) * seg_len;
285
286
		if (seg_type == AS_SET)
287
			if (total_size != 0)
288
				total_size += 3;
289
			else
290
				total_size += 2;
291
		else if (total_size != 0)
292
			total_size += 1;
293
294
		for (i = 0; i < seg_len; i++) {
295
			as = aspath_extract(seg, i);
296
297
			do {
298
				total_size++;
299
			} while ((as = as / 10) != 0);
300
301
			if (i + 1 < seg_len)
302
				total_size += 1;
303
		}
304
305
		if (seg_type == AS_SET)
306
			total_size += 2;
307
	}
308
	return (total_size);
309
}
310
311
/* we need to be able to search more than one as */
312
int
313
aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
314
{
315
	u_int8_t	*seg;
316
	int		 final;
317
	u_int16_t	 seg_size;
318
	u_int8_t	 i, seg_len;
319
	u_int32_t	 as;
320
321
	if (f->type == AS_EMPTY) {
322
		if (len == 0)
323
			return (1);
324
		else
325
			return (0);
326
	}
327
328
	seg = data;
329
	for (; len > 0; len -= seg_size, seg += seg_size) {
330
		seg_len = seg[1];
331
		seg_size = 2 + sizeof(u_int32_t) * seg_len;
332
333
		final = (len == seg_size);
334
335
		/* just check the first (leftmost) AS */
336
		if (f->type == AS_PEER) {
337
			as = aspath_extract(seg, 0);
338
			if (as_compare(f->op, as, match, f->as_min, f->as_max))
339
				return (1);
340
			else
341
				return (0);
342
		}
343
		/* just check the final (rightmost) AS */
344
		if (f->type == AS_SOURCE) {
345
			/* not yet in the final segment */
346
			if (!final)
347
				continue;
348
			as = aspath_extract(seg, seg_len - 1);
349
			if (as_compare(f->op, as, match, f->as_min, f->as_max))
350
				return (1);
351
			else
352
				return (0);
353
		}
354
		/* AS_TRANSIT or AS_ALL */
355
		for (i = 0; i < seg_len; i++) {
356
			/*
357
			 * the source (rightmost) AS is excluded from
358
			 * AS_TRANSIT matches.
359
			 */
360
			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
361
				return (0);
362
			as = aspath_extract(seg, i);
363
			if (as_compare(f->op, as, match, f->as_min, f->as_max))
364
				return (1);
365
		}
366
	}
367
	return (0);
368
}
369
370
int
371
as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min,
372
    u_int32_t as_max)
373
{
374
	if ((op == OP_NONE || op == OP_EQ) && as == match)
375
		return (1);
376
	else if (op == OP_NE && as != match)
377
		return (1);
378
	else if (op == OP_RANGE && as >= as_min && as <= as_max)
379
		return (1);
380
	else if (op == OP_XRANGE && as > as_min && as < as_max)
381
		return (1);
382
	return (0);
383
}
384
385
/*
386
 * Extract the asnum out of the as segment at the specified position.
387
 * Direct access is not possible because of non-aligned reads.
388
 * ATTENTION: no bounds checks are done.
389
 */
390
u_int32_t
391
aspath_extract(const void *seg, int pos)
392
{
393
	const u_char	*ptr = seg;
394
	u_int32_t	 as;
395
396
	ptr += 2 + sizeof(u_int32_t) * pos;
397
	memcpy(&as, ptr, sizeof(u_int32_t));
398
	return (ntohl(as));
399
}
400
401
/*
402
 * This function will have undefined behaviour if the passed in prefixlen is
403
 * to large for the respective bgpd_addr address family.
404
 */
405
int
406
prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
407
    int prefixlen)
408
{
409
	in_addr_t	mask, aa, ba;
410
	int		i;
411
	u_int8_t	m;
412
413
	if (a->aid != b->aid)
414
		return (a->aid - b->aid);
415
416
	switch (a->aid) {
417
	case AID_INET:
418
		if (prefixlen == 0)
419
			return (0);
420
		if (prefixlen > 32)
421
			return (-1);
422
		mask = htonl(prefixlen2mask(prefixlen));
423
		aa = ntohl(a->v4.s_addr & mask);
424
		ba = ntohl(b->v4.s_addr & mask);
425
		if (aa != ba)
426
			return (aa - ba);
427
		return (0);
428
	case AID_INET6:
429
		if (prefixlen == 0)
430
			return (0);
431
		if (prefixlen > 128)
432
			return (-1);
433
		for (i = 0; i < prefixlen / 8; i++)
434
			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
435
				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
436
		i = prefixlen % 8;
437
		if (i) {
438
			m = 0xff00 >> i;
439
			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
440
			    (b->v6.s6_addr[prefixlen / 8] & m))
441
				return ((a->v6.s6_addr[prefixlen / 8] & m) -
442
				    (b->v6.s6_addr[prefixlen / 8] & m));
443
		}
444
		return (0);
445
	case AID_VPN_IPv4:
446
		if (prefixlen > 32)
447
			return (-1);
448
		if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
449
			return (1);
450
		if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
451
			return (-1);
452
		mask = htonl(prefixlen2mask(prefixlen));
453
		aa = ntohl(a->vpn4.addr.s_addr & mask);
454
		ba = ntohl(b->vpn4.addr.s_addr & mask);
455
		if (aa != ba)
456
			return (aa - ba);
457
		if (a->vpn4.labellen > b->vpn4.labellen)
458
			return (1);
459
		if (a->vpn4.labellen < b->vpn4.labellen)
460
			return (-1);
461
		return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
462
		    a->vpn4.labellen));
463
	}
464
	return (-1);
465
}
466
467
in_addr_t
468
prefixlen2mask(u_int8_t prefixlen)
469
{
470
	if (prefixlen == 0)
471
		return (0);
472
473
	return (0xffffffff << (32 - prefixlen));
474
}
475
476
void
477
inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
478
{
479
	struct in6_addr	mask;
480
	int		i;
481
482
	bzero(&mask, sizeof(mask));
483
	for (i = 0; i < prefixlen / 8; i++)
484
		mask.s6_addr[i] = 0xff;
485
	i = prefixlen % 8;
486
	if (i)
487
		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
488
489
	for (i = 0; i < 16; i++)
490
		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
491
}
492
493
/* address family translation functions */
494
const struct aid aid_vals[AID_MAX] = AID_VALS;
495
496
const char *
497
aid2str(u_int8_t aid)
498
{
499
	if (aid < AID_MAX)
500
		return (aid_vals[aid].name);
501
	return ("unknown AID");
502
}
503
504
int
505
aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
506
{
507
	if (aid < AID_MAX) {
508
		*afi = aid_vals[aid].afi;
509
		*safi = aid_vals[aid].safi;
510
		return (0);
511
	}
512
	return (-1);
513
}
514
515
int
516
afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
517
{
518
	u_int8_t i;
519
520
	for (i = 0; i < AID_MAX; i++)
521
		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
522
			*aid = i;
523
			return (0);
524
		}
525
526
	return (-1);
527
}
528
529
sa_family_t
530
aid2af(u_int8_t aid)
531
{
532
	if (aid < AID_MAX)
533
		return (aid_vals[aid].af);
534
	return (AF_UNSPEC);
535
}
536
537
int
538
af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
539
{
540
	u_int8_t i;
541
542
	if (safi == 0) /* default to unicast subclass */
543
		safi = SAFI_UNICAST;
544
545
	for (i = 0; i < AID_MAX; i++)
546
		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
547
			*aid = i;
548
			return (0);
549
		}
550
551
	return (-1);
552
}
553
554
struct sockaddr *
555
addr2sa(struct bgpd_addr *addr, u_int16_t port)
556
{
557
	static struct sockaddr_storage	 ss;
558
	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
559
	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
560
561
	if (addr->aid == AID_UNSPEC)
562
		return (NULL);
563
564
	bzero(&ss, sizeof(ss));
565
	switch (addr->aid) {
566
	case AID_INET:
567
		sa_in->sin_family = AF_INET;
568
		sa_in->sin_len = sizeof(struct sockaddr_in);
569
		sa_in->sin_addr.s_addr = addr->v4.s_addr;
570
		sa_in->sin_port = htons(port);
571
		break;
572
	case AID_INET6:
573
		sa_in6->sin6_family = AF_INET6;
574
		sa_in6->sin6_len = sizeof(struct sockaddr_in6);
575
		memcpy(&sa_in6->sin6_addr, &addr->v6,
576
		    sizeof(sa_in6->sin6_addr));
577
		sa_in6->sin6_port = htons(port);
578
		sa_in6->sin6_scope_id = addr->scope_id;
579
		break;
580
	}
581
582
	return ((struct sockaddr *)&ss);
583
}
584
585
void
586
sa2addr(struct sockaddr *sa, struct bgpd_addr *addr)
587
{
588
	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
589
	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
590
591
	bzero(addr, sizeof(*addr));
592
	switch (sa->sa_family) {
593
	case AF_INET:
594
		addr->aid = AID_INET;
595
		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
596
		break;
597
	case AF_INET6:
598
		addr->aid = AID_INET6;
599
		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
600
		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
601
		break;
602
	}
603
}