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