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