GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/util.c Lines: 0 140 0.0 %
Date: 2017-11-13 Branches: 0 173 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: util.c,v 1.9 2016/09/02 16:36:33 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5
 * Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org>
6
 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
#include <sys/types.h>
23
24
#include <string.h>
25
26
#include "eigrpd.h"
27
#include "log.h"
28
29
uint8_t
30
mask2prefixlen(in_addr_t ina)
31
{
32
	if (ina == 0)
33
		return (0);
34
	else
35
		return (33 - ffs(ntohl(ina)));
36
}
37
38
uint8_t
39
mask2prefixlen6(struct sockaddr_in6 *sa_in6)
40
{
41
	uint8_t	l = 0, *ap, *ep;
42
43
	/*
44
	 * sin6_len is the size of the sockaddr so substract the offset of
45
	 * the possibly truncated sin6_addr struct.
46
	 */
47
	ap = (uint8_t *)&sa_in6->sin6_addr;
48
	ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
49
	for (; ap < ep; ap++) {
50
		/* this "beauty" is adopted from sbin/route/show.c ... */
51
		switch (*ap) {
52
		case 0xff:
53
			l += 8;
54
			break;
55
		case 0xfe:
56
			l += 7;
57
			return (l);
58
		case 0xfc:
59
			l += 6;
60
			return (l);
61
		case 0xf8:
62
			l += 5;
63
			return (l);
64
		case 0xf0:
65
			l += 4;
66
			return (l);
67
		case 0xe0:
68
			l += 3;
69
			return (l);
70
		case 0xc0:
71
			l += 2;
72
			return (l);
73
		case 0x80:
74
			l += 1;
75
			return (l);
76
		case 0x00:
77
			return (l);
78
		default:
79
			fatalx("non contiguous inet6 netmask");
80
		}
81
	}
82
83
	return (l);
84
}
85
86
in_addr_t
87
prefixlen2mask(uint8_t prefixlen)
88
{
89
	if (prefixlen == 0)
90
		return (0);
91
92
	return (htonl(0xffffffff << (32 - prefixlen)));
93
}
94
95
struct in6_addr *
96
prefixlen2mask6(uint8_t prefixlen)
97
{
98
	static struct in6_addr	mask;
99
	int			i;
100
101
	memset(&mask, 0, sizeof(mask));
102
	for (i = 0; i < prefixlen / 8; i++)
103
		mask.s6_addr[i] = 0xff;
104
	i = prefixlen % 8;
105
	if (i)
106
		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
107
108
	return (&mask);
109
}
110
111
void
112
eigrp_applymask(int af, union eigrpd_addr *dest, const union eigrpd_addr *src,
113
    int prefixlen)
114
{
115
	struct in6_addr	mask;
116
	int		i;
117
118
	switch (af) {
119
	case AF_INET:
120
		dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen);
121
		break;
122
	case AF_INET6:
123
		memset(&mask, 0, sizeof(mask));
124
		for (i = 0; i < prefixlen / 8; i++)
125
			mask.s6_addr[i] = 0xff;
126
		i = prefixlen % 8;
127
		if (i)
128
			mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
129
130
		for (i = 0; i < 16; i++)
131
			dest->v6.s6_addr[i] = src->v6.s6_addr[i] &
132
			    mask.s6_addr[i];
133
		break;
134
	default:
135
		fatalx("eigrp_applymask: unknown af");
136
	}
137
}
138
139
int
140
eigrp_addrcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b)
141
{
142
	switch (af) {
143
	case AF_INET:
144
		if (a->v4.s_addr == b->v4.s_addr)
145
			return (0);
146
		return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1);
147
	case AF_INET6:
148
		return (!!memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
149
	default:
150
		fatalx("eigrp_addrcmp: unknown af");
151
	}
152
}
153
154
int
155
eigrp_addrisset(int af, const union eigrpd_addr *addr)
156
{
157
	switch (af) {
158
	case AF_UNSPEC:
159
		return (0);
160
	case AF_INET:
161
		if (addr->v4.s_addr != INADDR_ANY)
162
			return (1);
163
		break;
164
	case AF_INET6:
165
		if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
166
			return (1);
167
		break;
168
	default:
169
		fatalx("eigrp_addrisset: unknown af");
170
	}
171
172
	return (0);
173
}
174
175
int
176
eigrp_prefixcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b,
177
    uint8_t prefixlen)
178
{
179
	in_addr_t	mask, aa, ba;
180
	int		i;
181
	uint8_t		m;
182
183
	switch (af) {
184
	case AF_INET:
185
		if (prefixlen == 0)
186
			return (0);
187
		if (prefixlen > 32)
188
			fatalx("eigrp_prefixcmp: bad IPv4 prefixlen");
189
		mask = htonl(prefixlen2mask(prefixlen));
190
		aa = htonl(a->v4.s_addr) & mask;
191
		ba = htonl(b->v4.s_addr) & mask;
192
		return (aa - ba);
193
	case AF_INET6:
194
		if (prefixlen == 0)
195
			return (0);
196
		if (prefixlen > 128)
197
			fatalx("eigrp_prefixcmp: bad IPv6 prefixlen");
198
		for (i = 0; i < prefixlen / 8; i++)
199
			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
200
				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
201
		i = prefixlen % 8;
202
		if (i) {
203
			m = 0xff00 >> i;
204
			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
205
			    (b->v6.s6_addr[prefixlen / 8] & m))
206
				return ((a->v6.s6_addr[prefixlen / 8] & m) -
207
				    (b->v6.s6_addr[prefixlen / 8] & m));
208
		}
209
		return (0);
210
	default:
211
		fatalx("eigrp_prefixcmp: unknown af");
212
	}
213
	return (-1);
214
}
215
216
int
217
bad_addr_v4(struct in_addr addr)
218
{
219
	uint32_t	 a = ntohl(addr.s_addr);
220
221
	if (((a >> IN_CLASSA_NSHIFT) == 0) ||
222
	    ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) ||
223
	    IN_MULTICAST(a) || IN_BADCLASS(a))
224
		return (1);
225
226
	return (0);
227
}
228
229
int
230
bad_addr_v6(struct in6_addr *addr)
231
{
232
	if (IN6_IS_ADDR_UNSPECIFIED(addr) ||
233
	    IN6_IS_ADDR_LOOPBACK(addr) ||
234
	    IN6_IS_ADDR_MULTICAST(addr) ||
235
	    IN6_IS_ADDR_SITELOCAL(addr) ||
236
	    IN6_IS_ADDR_V4MAPPED(addr) ||
237
	    IN6_IS_ADDR_V4COMPAT(addr))
238
		return (1);
239
240
	return (0);
241
}
242
243
int
244
bad_addr(int af, union eigrpd_addr *addr)
245
{
246
	switch (af) {
247
	case AF_INET:
248
		return (bad_addr_v4(addr->v4));
249
	case AF_INET6:
250
		return (bad_addr_v6(&addr->v6));
251
	default:
252
		fatalx("bad_addr: unknown af");
253
	}
254
}
255
256
void
257
embedscope(struct sockaddr_in6 *sin6)
258
{
259
	uint16_t	 tmp16;
260
261
	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
262
		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
263
		if (tmp16 != 0) {
264
			log_warnx("%s: address %s already has embeded scope %u",
265
			    __func__, log_sockaddr(sin6), ntohs(tmp16));
266
		}
267
		tmp16 = htons(sin6->sin6_scope_id);
268
		memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
269
		sin6->sin6_scope_id = 0;
270
	}
271
}
272
273
void
274
recoverscope(struct sockaddr_in6 *sin6)
275
{
276
	uint16_t	 tmp16;
277
278
	if (sin6->sin6_scope_id != 0)
279
		log_warnx("%s: address %s already has scope id %u",
280
		    __func__, log_sockaddr(sin6), sin6->sin6_scope_id);
281
282
	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
283
		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
284
		sin6->sin6_scope_id = ntohs(tmp16);
285
		sin6->sin6_addr.s6_addr[2] = 0;
286
		sin6->sin6_addr.s6_addr[3] = 0;
287
	}
288
}
289
290
void
291
addscope(struct sockaddr_in6 *sin6, uint32_t id)
292
{
293
	if (sin6->sin6_scope_id != 0)
294
		log_warnx("%s: address %s already has scope id %u", __func__,
295
		    log_sockaddr(sin6), sin6->sin6_scope_id);
296
297
	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr))
298
		sin6->sin6_scope_id = id;
299
}
300
301
void
302
clearscope(struct in6_addr *in6)
303
{
304
	if (IN6_IS_SCOPE_EMBED(in6)) {
305
		in6->s6_addr[2] = 0;
306
		in6->s6_addr[3] = 0;
307
	}
308
}
309
310
void
311
sa2addr(struct sockaddr *sa, int *af, union eigrpd_addr *addr)
312
{
313
	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
314
	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
315
316
	memset(addr, 0, sizeof(*addr));
317
	switch (sa->sa_family) {
318
	case AF_INET:
319
		*af = AF_INET;
320
		addr->v4 = sa_in->sin_addr;
321
		break;
322
	case AF_INET6:
323
		*af = AF_INET6;
324
		addr->v6 = sa_in6->sin6_addr;
325
		break;
326
	default:
327
		fatalx("sa2addr: unknown af");
328
	}
329
}