xref: /openbsd/usr.sbin/eigrpd/util.c (revision 3a50f0a9)
1 /*	$OpenBSD: util.c,v 1.12 2022/12/28 21:30:16 jmc 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
mask2prefixlen(in_addr_t ina)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
mask2prefixlen6(struct sockaddr_in6 * sa_in6)39 mask2prefixlen6(struct sockaddr_in6 *sa_in6)
40 {
41 	unsigned int l = 0;
42 	uint8_t *ap, *ep;
43 
44 	/*
45 	 * sin6_len is the size of the sockaddr so subtract the offset of
46 	 * the possibly truncated sin6_addr struct.
47 	 */
48 	ap = (uint8_t *)&sa_in6->sin6_addr;
49 	ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
50 	for (; ap < ep; ap++) {
51 		/* this "beauty" is adopted from sbin/route/show.c ... */
52 		switch (*ap) {
53 		case 0xff:
54 			l += 8;
55 			break;
56 		case 0xfe:
57 			l += 7;
58 			goto done;
59 		case 0xfc:
60 			l += 6;
61 			goto done;
62 		case 0xf8:
63 			l += 5;
64 			goto done;
65 		case 0xf0:
66 			l += 4;
67 			goto done;
68 		case 0xe0:
69 			l += 3;
70 			goto done;
71 		case 0xc0:
72 			l += 2;
73 			goto done;
74 		case 0x80:
75 			l += 1;
76 			goto done;
77 		case 0x00:
78 			goto done;
79 		default:
80 			fatalx("non contiguous inet6 netmask");
81 		}
82 	}
83 
84 done:
85 	if (l > sizeof(struct in6_addr) * 8)
86 		fatalx("inet6 prefixlen out of bound");
87 	return (l);
88 }
89 
90 in_addr_t
prefixlen2mask(uint8_t prefixlen)91 prefixlen2mask(uint8_t prefixlen)
92 {
93 	if (prefixlen == 0)
94 		return (0);
95 
96 	return (htonl(0xffffffff << (32 - prefixlen)));
97 }
98 
99 struct in6_addr *
prefixlen2mask6(uint8_t prefixlen)100 prefixlen2mask6(uint8_t prefixlen)
101 {
102 	static struct in6_addr	mask;
103 	int			i;
104 
105 	memset(&mask, 0, sizeof(mask));
106 	for (i = 0; i < prefixlen / 8; i++)
107 		mask.s6_addr[i] = 0xff;
108 	i = prefixlen % 8;
109 	if (i)
110 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
111 
112 	return (&mask);
113 }
114 
115 void
eigrp_applymask(int af,union eigrpd_addr * dest,const union eigrpd_addr * src,int prefixlen)116 eigrp_applymask(int af, union eigrpd_addr *dest, const union eigrpd_addr *src,
117     int prefixlen)
118 {
119 	struct in6_addr	mask;
120 	int		i;
121 
122 	switch (af) {
123 	case AF_INET:
124 		dest->v4.s_addr = src->v4.s_addr & prefixlen2mask(prefixlen);
125 		break;
126 	case AF_INET6:
127 		memset(&mask, 0, sizeof(mask));
128 		for (i = 0; i < prefixlen / 8; i++)
129 			mask.s6_addr[i] = 0xff;
130 		i = prefixlen % 8;
131 		if (i)
132 			mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
133 
134 		for (i = 0; i < 16; i++)
135 			dest->v6.s6_addr[i] = src->v6.s6_addr[i] &
136 			    mask.s6_addr[i];
137 		break;
138 	default:
139 		fatalx("eigrp_applymask: unknown af");
140 	}
141 }
142 
143 int
eigrp_addrcmp(int af,const union eigrpd_addr * a,const union eigrpd_addr * b)144 eigrp_addrcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b)
145 {
146 	switch (af) {
147 	case AF_INET:
148 		if (a->v4.s_addr == b->v4.s_addr)
149 			return (0);
150 		return ((ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr)) ? 1 : -1);
151 	case AF_INET6:
152 		return (!!memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
153 	default:
154 		fatalx("eigrp_addrcmp: unknown af");
155 	}
156 }
157 
158 int
eigrp_addrisset(int af,const union eigrpd_addr * addr)159 eigrp_addrisset(int af, const union eigrpd_addr *addr)
160 {
161 	switch (af) {
162 	case AF_UNSPEC:
163 		return (0);
164 	case AF_INET:
165 		if (addr->v4.s_addr != INADDR_ANY)
166 			return (1);
167 		break;
168 	case AF_INET6:
169 		if (!IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
170 			return (1);
171 		break;
172 	default:
173 		fatalx("eigrp_addrisset: unknown af");
174 	}
175 
176 	return (0);
177 }
178 
179 int
eigrp_prefixcmp(int af,const union eigrpd_addr * a,const union eigrpd_addr * b,uint8_t prefixlen)180 eigrp_prefixcmp(int af, const union eigrpd_addr *a, const union eigrpd_addr *b,
181     uint8_t prefixlen)
182 {
183 	in_addr_t	mask, aa, ba;
184 	int		i;
185 	uint8_t		m;
186 
187 	switch (af) {
188 	case AF_INET:
189 		if (prefixlen == 0)
190 			return (0);
191 		if (prefixlen > 32)
192 			fatalx("eigrp_prefixcmp: bad IPv4 prefixlen");
193 		mask = htonl(prefixlen2mask(prefixlen));
194 		aa = htonl(a->v4.s_addr) & mask;
195 		ba = htonl(b->v4.s_addr) & mask;
196 		return (aa - ba);
197 	case AF_INET6:
198 		if (prefixlen == 0)
199 			return (0);
200 		if (prefixlen > 128)
201 			fatalx("eigrp_prefixcmp: bad IPv6 prefixlen");
202 		for (i = 0; i < prefixlen / 8; i++)
203 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
204 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
205 		i = prefixlen % 8;
206 		if (i) {
207 			m = 0xff00 >> i;
208 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
209 			    (b->v6.s6_addr[prefixlen / 8] & m))
210 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
211 				    (b->v6.s6_addr[prefixlen / 8] & m));
212 		}
213 		return (0);
214 	default:
215 		fatalx("eigrp_prefixcmp: unknown af");
216 	}
217 	return (-1);
218 }
219 
220 int
bad_addr_v4(struct in_addr addr)221 bad_addr_v4(struct in_addr addr)
222 {
223 	uint32_t	 a = ntohl(addr.s_addr);
224 
225 	if (((a >> IN_CLASSA_NSHIFT) == 0) ||
226 	    ((a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) ||
227 	    IN_MULTICAST(a))
228 		return (1);
229 
230 	return (0);
231 }
232 
233 int
bad_addr_v6(struct in6_addr * addr)234 bad_addr_v6(struct in6_addr *addr)
235 {
236 	if (IN6_IS_ADDR_UNSPECIFIED(addr) ||
237 	    IN6_IS_ADDR_LOOPBACK(addr) ||
238 	    IN6_IS_ADDR_MULTICAST(addr) ||
239 	    IN6_IS_ADDR_SITELOCAL(addr) ||
240 	    IN6_IS_ADDR_V4MAPPED(addr) ||
241 	    IN6_IS_ADDR_V4COMPAT(addr))
242 		return (1);
243 
244 	return (0);
245 }
246 
247 int
bad_addr(int af,union eigrpd_addr * addr)248 bad_addr(int af, union eigrpd_addr *addr)
249 {
250 	switch (af) {
251 	case AF_INET:
252 		return (bad_addr_v4(addr->v4));
253 	case AF_INET6:
254 		return (bad_addr_v6(&addr->v6));
255 	default:
256 		fatalx("bad_addr: unknown af");
257 	}
258 }
259 
260 void
embedscope(struct sockaddr_in6 * sin6)261 embedscope(struct sockaddr_in6 *sin6)
262 {
263 	uint16_t	 tmp16;
264 
265 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
266 		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
267 		if (tmp16 != 0) {
268 			log_warnx("%s: address %s already has embedded scope %u",
269 			    __func__, log_sockaddr(sin6), ntohs(tmp16));
270 		}
271 		tmp16 = htons(sin6->sin6_scope_id);
272 		memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
273 		sin6->sin6_scope_id = 0;
274 	}
275 }
276 
277 void
recoverscope(struct sockaddr_in6 * sin6)278 recoverscope(struct sockaddr_in6 *sin6)
279 {
280 	uint16_t	 tmp16;
281 
282 	if (sin6->sin6_scope_id != 0)
283 		log_warnx("%s: address %s already has scope id %u",
284 		    __func__, log_sockaddr(sin6), sin6->sin6_scope_id);
285 
286 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
287 		memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
288 		sin6->sin6_scope_id = ntohs(tmp16);
289 		sin6->sin6_addr.s6_addr[2] = 0;
290 		sin6->sin6_addr.s6_addr[3] = 0;
291 	}
292 }
293 
294 void
addscope(struct sockaddr_in6 * sin6,uint32_t id)295 addscope(struct sockaddr_in6 *sin6, uint32_t id)
296 {
297 	if (sin6->sin6_scope_id != 0)
298 		log_warnx("%s: address %s already has scope id %u", __func__,
299 		    log_sockaddr(sin6), sin6->sin6_scope_id);
300 
301 	if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr))
302 		sin6->sin6_scope_id = id;
303 }
304 
305 void
clearscope(struct in6_addr * in6)306 clearscope(struct in6_addr *in6)
307 {
308 	if (IN6_IS_SCOPE_EMBED(in6)) {
309 		in6->s6_addr[2] = 0;
310 		in6->s6_addr[3] = 0;
311 	}
312 }
313 
314 void
sa2addr(struct sockaddr * sa,int * af,union eigrpd_addr * addr)315 sa2addr(struct sockaddr *sa, int *af, union eigrpd_addr *addr)
316 {
317 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
318 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
319 
320 	memset(addr, 0, sizeof(*addr));
321 	switch (sa->sa_family) {
322 	case AF_INET:
323 		*af = AF_INET;
324 		addr->v4 = sa_in->sin_addr;
325 		break;
326 	case AF_INET6:
327 		*af = AF_INET6;
328 		addr->v6 = sa_in6->sin6_addr;
329 		break;
330 	default:
331 		fatalx("sa2addr: unknown af");
332 	}
333 }
334