GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpctl/irr_prefix.c Lines: 0 131 0.0 %
Date: 2016-12-06 Branches: 0 316 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: irr_prefix.c,v 1.21 2015/10/05 14:18:33 deraadt Exp $ */
2
3
/*
4
 * Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
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 MIND, USE, DATA OR PROFITS, WHETHER IN
15
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <err.h>
21
#include <errno.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
#include <netinet/in.h>
27
#include <arpa/inet.h>
28
29
#include "irrfilter.h"
30
#include "bgpd.h"
31
32
void	 prefixset_aggregate(struct prefix_set *);
33
int	 prefix_aggregate(struct irr_prefix *, const struct irr_prefix *);
34
int	 irr_prefix_cmp(const void *, const void *);
35
int	 prefix_set_compare(struct prefix_set *, struct prefix_set *);
36
struct prefix_set
37
	*prefix_set_find(char *);
38
39
RB_HEAD(prefix_set_h, prefix_set)	prefix_set_h;
40
RB_PROTOTYPE(prefix_set_h, prefix_set, entry, prefix_set_compare)
41
RB_GENERATE(prefix_set_h, prefix_set, entry, prefix_set_compare)
42
43
struct prefix_set	*curpfxs = NULL;
44
45
struct prefix_set *
46
prefixset_get(char *as)
47
{
48
	struct prefix_set	*pfxs;
49
50
	if ((pfxs = prefix_set_find(as)) != NULL)
51
		return (pfxs);
52
53
	/* nothing found, resolve and store */
54
	if ((pfxs = calloc(1, sizeof(*pfxs))) == NULL)
55
		err(1, "get_prefixset calloc");
56
	if ((pfxs->as = strdup(as)) == NULL)
57
		err(1, "get_prefixset strdup");
58
	RB_INSERT(prefix_set_h, &prefix_set_h, pfxs);
59
60
	if (irrverbose >= 3) {
61
		fprintf(stdout, "query routes for %s... ", as);
62
		fflush(stdout);
63
	}
64
	curpfxs = pfxs;
65
	if ((irrflags & F_IPV4) && whois(as, QTYPE_ROUTE) == -1)
66
		errx(1, "whois error, prefixset_get %s", as);
67
	if ((irrflags & F_IPV6) && whois(as, QTYPE_ROUTE6) == -1)
68
		errx(1, "whois error, prefixset_get %s", as);
69
	if (whois(as, QTYPE_ROUTE6) == -1)
70
		errx(1, "whois error, prefixset_get %s", as);
71
	curpfxs = NULL;
72
	if (irrverbose >= 3)
73
		fprintf(stdout, "done\n");
74
75
	prefixset_aggregate(pfxs);
76
77
	return (pfxs);
78
}
79
80
int
81
prefixset_addmember(char *s)
82
{
83
	void			*p;
84
	u_int			 i;
85
	struct irr_prefix	*pfx;
86
	int			 len, ret;
87
	char			*slash;
88
	const char		*errstr;
89
90
	if ((slash = strchr(s, '/')) == NULL) {
91
		fprintf(stderr, "%s: prefix %s does not have the len "
92
		    "specified, ignoring\n", curpfxs->as, s);
93
		return (0);
94
	}
95
96
	if ((pfx = calloc(1, sizeof(*pfx))) == NULL)
97
		err(1, "prefixset_addmember calloc");
98
99
	if ((len = inet_net_pton(AF_INET, s, &pfx->addr.in,
100
	    sizeof(pfx->addr.in))) != -1) {
101
		pfx->af = AF_INET;
102
	} else {
103
		len = strtonum(slash + 1, 0, 128, &errstr);
104
		if (errstr)
105
			errx(1, "prefixset_addmember %s prefix %s: prefixlen "
106
			    "is %s", curpfxs->as, s, errstr);
107
		*slash = '\0';
108
109
		if ((ret = inet_pton(AF_INET6, s, &pfx->addr.in6)) == -1)
110
			err(1, "prefixset_addmember %s prefix \"%s\"",
111
			    curpfxs->as, s);
112
		else if (ret == 0) {
113
			fprintf(stderr, "prefixset_addmember %s prefix \"%s\": "
114
			    "No matching address family found", curpfxs->as, s);
115
			free(pfx);
116
			return (0);
117
		}
118
		pfx->af = AF_INET6;
119
	}
120
	pfx->len = pfx->maxlen = len;
121
122
	/* yes, there are dupes... e. g. from multiple sources */
123
	for (i = 0; i < curpfxs->prefixcnt; i++)
124
		if (irr_prefix_cmp(&curpfxs->prefix[i], &pfx) == 0) {
125
			free(pfx);
126
			return (0);
127
		}
128
129
	if ((p = reallocarray(curpfxs->prefix,
130
	    curpfxs->prefixcnt + 1, sizeof(void *))) == NULL)
131
		err(1, "prefixset_addmember realloc");
132
	curpfxs->prefix = p;
133
	curpfxs->prefixcnt++;
134
	curpfxs->prefix[curpfxs->prefixcnt - 1] = pfx;
135
136
	return (1);
137
}
138
139
void
140
prefixset_aggregate(struct prefix_set *pfxs)
141
{
142
	u_int			 i, cnt, newcnt;
143
	int			 res;
144
	struct irr_prefix	*cur, *last;
145
	void			*p;
146
147
	qsort(pfxs->prefix, pfxs->prefixcnt, sizeof(void *), irr_prefix_cmp);
148
149
	cnt = pfxs->prefixcnt;
150
	do {
151
		last = cur = NULL;
152
		for (i = 0, newcnt = 0; i < cnt; i++) {
153
			cur = pfxs->prefix[i];
154
			if (last != NULL && last->af == cur->af) {
155
				if (cur->af == AF_INET)
156
					res = prefix_aggregate(last, cur);
157
				else
158
					res = 0;
159
160
				if (res == 1) {	/* cur is covered by last */
161
					if (cur->len > last->maxlen)
162
						last->maxlen = cur->len;
163
					free(pfxs->prefix[i]);
164
					pfxs->prefix[i] = cur = NULL;
165
				}
166
			}
167
168
			if (cur != NULL) {
169
				pfxs->prefix[newcnt++] = cur;
170
				last = cur;
171
			}
172
		}
173
		cnt = newcnt;
174
	} while (newcnt < i);
175
176
	if (newcnt == pfxs->prefixcnt)
177
		return;
178
179
	if (irrverbose >= 2)
180
		printf("%s: prefix aggregation: %u -> %u\n",
181
		    pfxs->as, pfxs->prefixcnt, newcnt);
182
183
	if ((p = reallocarray(pfxs->prefix, newcnt, sizeof(void *))) == NULL)
184
		err(1, "prefixset_aggregate realloc");
185
	pfxs->prefix = p;
186
	pfxs->prefixcnt = newcnt;
187
}
188
189
int
190
prefix_aggregate(struct irr_prefix *a, const struct irr_prefix *b)
191
{
192
	in_addr_t	 mask;
193
	struct in6_addr	 ma;
194
	struct in6_addr	 mb;
195
196
	if (a->len == 0)
197
		return (1);
198
199
	if (a->af != b->af)
200
		/* We cannot aggregate addresses of different families. */
201
		return (0);
202
203
	if (a->af == AF_INET) {
204
		mask = htonl(prefixlen2mask(a->len));
205
		if ((a->addr.in.s_addr & mask) == (b->addr.in.s_addr & mask))
206
			return (1);
207
	} else if (a->af == AF_INET6) {
208
		inet6applymask(&ma, &a->addr.in6, a->len);
209
		inet6applymask(&mb, &b->addr.in6, a->len);
210
		if (IN6_ARE_ADDR_EQUAL(&ma, &mb))
211
			return (1);
212
	}
213
214
	/* see whether we can fold them in one */
215
	if (a->len == b->len && a->len > 1) {
216
		if (a->af == AF_INET) {
217
			mask = htonl(prefixlen2mask(a->len - 1));
218
			if ((a->addr.in.s_addr & mask) ==
219
			    (b->addr.in.s_addr & mask)) {
220
				a->len--;
221
				a->addr.in.s_addr &= mask;
222
				return (1);
223
			}
224
		} else if (a->af == AF_INET6) {
225
			inet6applymask(&ma, &a->addr.in6, a->len - 1);
226
			inet6applymask(&mb, &b->addr.in6, a->len - 1);
227
228
			if (IN6_ARE_ADDR_EQUAL(&ma, &mb)) {
229
				a->len--;
230
				memcpy(&a->addr.in6, &ma, sizeof(ma));
231
				return (1);
232
			}
233
		}
234
	}
235
236
	return (0);
237
}
238
239
int
240
irr_prefix_cmp(const void *a, const void *b)
241
{
242
	const struct irr_prefix	*pa;
243
	const struct irr_prefix	*pb;
244
	int			 r;
245
246
	pa = *((const struct irr_prefix	* const *)a);
247
	pb = *((const struct irr_prefix	* const *)b);
248
249
	if ((r = pa->af - pb->af) != 0)
250
		return (r);
251
252
	if (pa->af == AF_INET) {
253
		if (ntohl(pa->addr.in.s_addr) <
254
		    ntohl(pb->addr.in.s_addr))
255
			return (-1);
256
		if (ntohl(pa->addr.in.s_addr) >
257
		    ntohl(pb->addr.in.s_addr))
258
			return (1);
259
	} else if (pa->af == AF_INET6) {
260
		for (r = 0; r < 16; r++) {
261
			if (pa->addr.in6.s6_addr[r] < pb->addr.in6.s6_addr[r])
262
				return (-1);
263
			if (pa->addr.in6.s6_addr[r] > pb->addr.in6.s6_addr[r])
264
				return (1);
265
		}
266
	} else
267
		errx(1, "irr_prefix_cmp unknown af %u", pa->af);
268
269
	if ((r = pa->len - pb->len) != 0)
270
		return (r);
271
272
	return (0);
273
}
274
275
/* RB helpers */
276
int
277
prefix_set_compare(struct prefix_set *a, struct prefix_set *b)
278
{
279
	return (strcmp(a->as, b->as));
280
}
281
282
struct prefix_set *
283
prefix_set_find(char *as)
284
{
285
	struct prefix_set	s;
286
287
	s.as = as;
288
	return (RB_FIND(prefix_set_h, &prefix_set_h, &s));
289
}