]>
Commit | Line | Data |
---|---|---|
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 | ||
27 | uint8_t | |
28 | mask2prefixlen(in_addr_t ina) | |
29 | { | |
30 | if (ina == 0) | |
31 | return (0); | |
32 | else | |
33 | return (33 - ffs(ntohl(ina))); | |
34 | } | |
35 | ||
36 | uint8_t | |
37 | mask2prefixlen6(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 | ||
84 | in_addr_t | |
85 | prefixlen2mask(uint8_t prefixlen) | |
86 | { | |
87 | if (prefixlen == 0) | |
88 | return (0); | |
89 | ||
90 | return (htonl(0xffffffff << (32 - prefixlen))); | |
91 | } | |
92 | ||
93 | struct in6_addr * | |
94 | prefixlen2mask6(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 | ||
109 | void | |
110 | ldp_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 | ||
137 | int | |
138 | ldp_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 | ||
152 | int | |
153 | ldp_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 | ||
173 | int | |
174 | ldp_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 | ||
214 | int | |
215 | bad_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 | ||
227 | int | |
228 | bad_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 | ||
241 | int | |
242 | bad_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 | ||
254 | void | |
255 | embedscope(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 | ||
271 | void | |
272 | recoverscope(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 | ||
288 | void | |
289 | addscope(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 | ||
299 | void | |
300 | clearscope(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 |
308 | void |
309 | addr2sa(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 | ||
337 | void | |
eac6e3f0 | 338 | sa2addr(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 | |
367 | socklen_t | |
368 | sockaddr_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 | } |