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