xref: /openbsd-src/usr.sbin/eigrpd/util.c (revision 897fc685943471cf985a0fe38ba076ea6fe74fa5)
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 }
330