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