]>
Commit | Line | Data |
---|---|---|
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 | ||
16 | uint8_t | |
17 | mask2prefixlen(in_addr_t ina) | |
18 | { | |
19 | if (ina == 0) | |
20 | return (0); | |
21 | else | |
22 | return (33 - ffs(ntohl(ina))); | |
23 | } | |
24 | ||
25 | uint8_t | |
26 | mask2prefixlen6(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 | ||
73 | in_addr_t | |
74 | prefixlen2mask(uint8_t prefixlen) | |
75 | { | |
76 | if (prefixlen == 0) | |
77 | return (0); | |
78 | ||
79 | return (htonl(0xffffffff << (32 - prefixlen))); | |
80 | } | |
81 | ||
82 | struct in6_addr * | |
83 | prefixlen2mask6(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 | ||
98 | void | |
99 | ldp_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 | ||
126 | int | |
127 | ldp_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 | ||
141 | int | |
142 | ldp_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 | ||
162 | int | |
163 | ldp_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 | ||
203 | int | |
204 | bad_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 | ||
216 | int | |
217 | bad_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 | ||
230 | int | |
231 | bad_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 | ||
243 | void | |
244 | embedscope(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 | ||
260 | void | |
261 | recoverscope(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 | ||
277 | void | |
278 | addscope(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 | ||
288 | void | |
289 | clearscope(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 |
297 | void |
298 | addr2sa(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 | ||
326 | void | |
eac6e3f0 | 327 | sa2addr(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 | |
356 | socklen_t | |
357 | sockaddr_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 | } |