blob: 448121ff604acb95823e2fa0530f763ba6949e95 [file] [log] [blame]
Lorenzo Colitti313379e2013-07-11 01:07:11 +09001/* $USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $ */
2/*
3 * Copyright (C) 2002 USAGI/WIDE Project.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30/*
31 * Author:
32 * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
33 */
34
35#if HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#if HAVE_SYS_TYPES_H
40# include <sys/types.h>
41#endif
42
43#if STDC_HEADERS
44# include <stdio.h>
45# include <stdlib.h>
46# include <stddef.h>
47#else
48# if HAVE_STDLIB_H
49# include <stdlib.h>
50# endif
51#endif
52#if HAVE_STRING_H
53# if !STDC_HEADERS && HAVE_MEMORY_H
54# include <memory.h>
55# endif
56# include <string.h>
57#endif
58#if HAVE_STRINGS_H
59# include <strings.h>
60#endif
61#if HAVE_INTTYPES_H
62# include <inttypes.h>
63#else
64# if HAVE_STDINT_H
65# include <stdint.h>
66# endif
67#endif
68#if HAVE_UNISTD_H
69# include <unistd.h>
70#endif
71
72#if TIME_WITH_SYS_TIME
73# include <sys/time.h>
74# include <time.h>
75#else
76# if HAVE_SYS_TIME_H
77# include <sys/time.h>
78# else
79# include <time.h>
80# endif
81#endif
82
83#if HAVE_SYS_UIO_H
84#include <sys/uio.h>
85#endif
86
87#include <sys/socket.h>
88#if HAVE_LINUX_RTNETLINK_H
89#include <asm/types.h>
90#include <linux/rtnetlink.h>
91#endif
92
93#if HAVE_NETINET_IN_H
94# include <netinet/in.h>
95#endif
96
97#if HAVE_NETINET_IP6_H
98# include <netinet/ip6.h>
99#endif
100
101#if HAVE_NETINET_ICMP6_H
102# include <netinet/icmp6.h>
103#endif
104#ifndef HAVE_STRUCT_ICMP6_NODEINFO
105# include "icmp6_nodeinfo.h"
106#endif
107
108#if HAVE_NETDB_H
109# include <netdb.h>
110#endif
111#include <errno.h>
112
113#if HAVE_SYSLOG_H
114# include <syslog.h>
115#endif
116
117#include "ninfod.h"
118#include "ni_ifaddrs.h"
119
120#ifndef offsetof
121# define offsetof(aggregate,member) ((size_t)&((aggregate *)0)->member)
122#endif
123
124/* ---------- */
125/* ID */
126static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $";
127
128/* ---------- */
129/* ipv6 address */
130void init_nodeinfo_ipv6addr(INIT_ARGS)
131{
132 DEBUG(LOG_DEBUG, "%s()\n", __func__);
133 return;
134}
135
136int filter_ipv6addr(const struct in6_addr *ifaddr, unsigned int flags)
137{
138 if (IN6_IS_ADDR_UNSPECIFIED(ifaddr) ||
139 IN6_IS_ADDR_LOOPBACK(ifaddr)) {
140 return 1;
141 } else if (IN6_IS_ADDR_V4COMPAT(ifaddr) ||
142 IN6_IS_ADDR_V4MAPPED(ifaddr)) {
143 return !(flags & NI_NODEADDR_FLAG_COMPAT);
144 } else if (IN6_IS_ADDR_LINKLOCAL(ifaddr)) {
145 return !(flags & NI_NODEADDR_FLAG_LINKLOCAL);
146 } else if (IN6_IS_ADDR_SITELOCAL(ifaddr)) {
147 return !(flags & NI_NODEADDR_FLAG_SITELOCAL);
148 }
149 return !(flags & NI_NODEADDR_FLAG_GLOBAL);
150}
151
152int pr_nodeinfo_ipv6addr(CHECKANDFILL_ARGS)
153{
154 struct ni_ifaddrs *ifa0;
155 unsigned int ifindex = 0;
156
157 DEBUG(LOG_DEBUG, "%s()\n", __func__);
158
159 if (subject && subjlen != sizeof(struct in6_addr)) {
160 DEBUG(LOG_INFO,
161 "%s(): invalid subject length %zu for IPv6 Address Subject\n",
162 __func__, subjlen);
163 return 1;
164 }
165 if (ni_ifaddrs(&ifa0, AF_INET6))
166 return -1; /* failed to get addresses */
167
168 /* pass 0: consider subject and determine subjected interface */
169 if (subject) {
170 struct ni_ifaddrs *ifa;
171
172 for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
173 if (!ifa->ifa_addr)
174 continue;
175 if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
176 continue;
177 if (!ifindex &&
178 IN6_ARE_ADDR_EQUAL(&p->pktinfo.ipi6_addr,
179 (struct in6_addr *)subject)) {
180 /*
181 * if subject is equal to destination
182 * address, receiving interface is
183 * the candidate subject interface.
184 */
185 ifindex = p->pktinfo.ipi6_ifindex;
186 }
187 if (!IN6_IS_ADDR_LOOPBACK((struct in6_addr *)subject) &&
188 IN6_ARE_ADDR_EQUAL((struct in6_addr *)ifa->ifa_addr,
189 (struct in6_addr *)subject)) {
190 /*
191 * address is assigned on some interface.
192 * if multiple interfaces have the same interface,
193 * 1) prefer receiving interface
194 * 2) use first found one
195 */
196 if (!ifindex ||
197 (p->pktinfo.ipi6_ifindex == ifindex))
198 ifindex = ifa->ifa_ifindex;
199 }
200 }
201 if (!ifindex) {
202 ni_freeifaddrs(ifa0);
203 return 1; /* subject not found */
204 }
205 if (subj_if)
206 *subj_if = ifindex;
207 } else {
208 ifindex = subj_if ? *subj_if : 0;
209 if (ifindex == 0)
210 ifindex = p->pktinfo.ipi6_ifindex;
211 if (ifindex == 0) {
212 ni_freeifaddrs(ifa0);
213 return 1; /* XXX */
214 }
215 }
216
217 if (reply) {
218 struct ni_ifaddrs *ifa;
219 unsigned int addrs0 = 0, paddrs0 = 0;
220 unsigned int addrs, paddrs = 0, daddrs = 0;
221
222 flags &= ~NI_NODEADDR_FLAG_TRUNCATE;
223
224 /* pass 1: count addresses and preferred addresses to be returned */
225 for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
226 if (!ifa->ifa_addr)
227 continue;
228 if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
229 continue;
230 if (!(flags & NI_NODEADDR_FLAG_ALL) &&
231 ifa->ifa_ifindex != ifindex)
232 continue;
233 if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
234 continue;
235
236 if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in6_addr)))) {
237 flags |= ~NI_NODEADDR_FLAG_TRUNCATE;
238 break;
239 }
240
241 addrs0++;
242 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
243 paddrs0++;
244 }
245
246 p->reply.ni_type = ICMP6_NI_REPLY;
247 p->reply.ni_code = ICMP6_NI_SUCCESS;
248 p->reply.ni_cksum = 0;
249 p->reply.ni_qtype = htons(NI_QTYPE_NODEADDR);
250 p->reply.ni_flags = flags&(NI_NODEADDR_FLAG_COMPAT|
251 NI_NODEADDR_FLAG_LINKLOCAL|
252 NI_NODEADDR_FLAG_SITELOCAL|
253 NI_NODEADDR_FLAG_GLOBAL);
254
255 /* pass 2: store addresses */
256 p->replydatalen = (sizeof(uint32_t)+sizeof(struct in6_addr)) * addrs0;
257 p->replydata = p->replydatalen ? ni_malloc(p->replydatalen) : NULL;
258
259 if (p->replydatalen && !p->replydata) {
260 p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
261 addrs0 = paddrs0 = 0;
262 }
263
264 for (ifa = ifa0, addrs = 0;
265 ifa && addrs < addrs0;
266 ifa = ifa->ifa_next) {
267 char *cp;
268 uint32_t ttl;
269
270 if (!ifa->ifa_addr)
271 continue;
272 if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
273 continue;
274 if (!(flags & NI_NODEADDR_FLAG_ALL) &&
275 ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
276 (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
277 continue;
278 if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
279 continue;
280
281#if ENABLE_TTL
282 if (ifa->ifa_cacheinfo) {
283 ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ?
284 htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
285 } else {
286 ttl = (ifa->ifa_flags & IFA_F_PERMANENT) ? htonl(0x7fffffff) : 0;
287 }
288#else
289 ttl = 0;
290#endif
291
292 cp = p->replydata +
293 (sizeof(uint32_t)+sizeof(struct in6_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs);
294 memcpy(cp, &ttl, sizeof(ttl));
295 memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in6_addr));
296
297 addrs++;
298 if (ifa->ifa_flags & IFA_F_DEPRECATED)
299 daddrs++;
300 else
301 paddrs++;
302 }
303 }
304
305 ni_freeifaddrs(ifa0);
306 return 0;
307}
308
309/* ipv4 address */
310void init_nodeinfo_ipv4addr(INIT_ARGS)
311{
312 DEBUG(LOG_DEBUG, "%s()\n", __func__);
313 return;
314}
315
316int filter_ipv4addr(const struct in_addr *ifaddr, unsigned int flags)
317{
318 return 0;
319}
320
321int pr_nodeinfo_ipv4addr(CHECKANDFILL_ARGS)
322{
323 struct ni_ifaddrs *ifa0;
324 unsigned int ifindex = 0;
325
326 DEBUG(LOG_DEBUG, "%s()\n", __func__);
327
328 if (subject && subjlen != sizeof(struct in_addr)) {
329 DEBUG(LOG_INFO,
330 "%s(): invalid subject length %zu for IPv4 Address Subject\n",
331 __func__, subjlen);
332 return 1;
333 }
334 if (ni_ifaddrs(&ifa0, AF_INET))
335 return -1; /* failed to get addresses */
336
337 /* pass 0: consider subject and determine subjected interface */
338 if (subject) {
339 struct ni_ifaddrs *ifa;
340
341 for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
342 if (!ifa->ifa_addr)
343 continue;
344 if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
345 continue;
346 if ((((struct in_addr *)subject)->s_addr != htonl(INADDR_LOOPBACK)) &&
347 memcmp((struct in_addr *)ifa->ifa_addr,
348 (struct in_addr *)subject,
349 sizeof(struct in_addr)) == 0) {
350 /*
351 * address is assigned on some interface.
352 * if multiple interfaces have the same interface,
353 * 1) prefer receiving interface
354 * 2) use first found one
355 */
356 if (!ifindex ||
357 (p->pktinfo.ipi6_ifindex == ifindex))
358 ifindex = ifa->ifa_ifindex;
359 }
360 }
361 if (!ifindex) {
362 ni_freeifaddrs(ifa0);
363 return 1; /* subject not found */
364 }
365 if (subj_if)
366 *subj_if = ifindex;
367 } else {
368 ifindex = subj_if ? *subj_if : 0;
369 if (ifindex == 0)
370 ifindex = p->pktinfo.ipi6_ifindex;
371 if (ifindex == 0) {
372 ni_freeifaddrs(ifa0);
373 return 1; /* XXX */
374 }
375 }
376
377 if (reply) {
378 struct ni_ifaddrs *ifa;
379 unsigned int addrs0 = 0, paddrs0 = 0;
380 unsigned int addrs, paddrs = 0, daddrs = 0;
381
382 flags &= ~NI_IPV4ADDR_FLAG_TRUNCATE;
383
384 /* pass 1: count addresses and preferred addresses to be returned */
385 for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
386 if (!ifa->ifa_addr)
387 continue;
388#if 1 /* not used in kernel */
389 if (ifa->ifa_flags & (IFA_F_TENTATIVE))
390 continue;
391#endif
392 if (!(flags & NI_NODEADDR_FLAG_ALL) &&
393 ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
394 (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
395 continue;
396 if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
397 continue;
398
399 if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in_addr)))) {
400 flags |= NI_IPV4ADDR_FLAG_TRUNCATE;
401 break;
402 }
403
404 addrs0++;
405 if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
406 paddrs0++;
407 }
408
409 p->reply.ni_type = ICMP6_NI_REPLY;
410 p->reply.ni_code = ICMP6_NI_SUCCESS;
411 p->reply.ni_cksum = 0;
412 p->reply.ni_qtype = htons(NI_QTYPE_IPV4ADDR);
413 p->reply.ni_flags = flags & NI_IPV4ADDR_FLAG_ALL;
414
415 /* pass 2: store addresses */
416 p->replydatalen = (sizeof(uint32_t)+sizeof(struct in_addr)) * addrs0;
417 p->replydata = addrs0 ? ni_malloc(p->replydatalen) : NULL;
418
419 if (p->replydatalen && !p->replydata) {
420 p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
421 addrs0 = paddrs0 = 0;
422 }
423
424 for (ifa = ifa0, addrs = 0;
425 ifa && addrs < addrs0;
426 ifa = ifa->ifa_next) {
427 char *cp;
428 uint32_t ttl;
429
430 if (!ifa->ifa_addr)
431 continue;
432#if 1 /* not used in kernel */
433 if (ifa->ifa_flags & (IFA_F_TENTATIVE))
434 continue;
435#endif
436 if (!(flags & NI_NODEADDR_FLAG_ALL) &&
437 (ifa->ifa_ifindex != ifindex))
438 continue;
439 if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
440 continue;
441
442#if ENABLE_TTL
443 if (ifa->ifa_cacheinfo) {
444 ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ?
445 htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
446 } else {
447 ttl = 0; /*XXX*/
448 }
449#else
450 ttl = 0;
451#endif
452
453 cp = (p->replydata +
454 (sizeof(uint32_t)+sizeof(struct in_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs));
455 memcpy(cp, &ttl, sizeof(ttl));
456 memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in_addr));
457
458 addrs++;
459 if (ifa->ifa_flags & IFA_F_DEPRECATED)
460 daddrs++;
461 else
462 paddrs++;
463 }
464 }
465
466 ni_freeifaddrs(ifa0);
467 return 0;
468}
469