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