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