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