af_inet6.c revision 1.5.16.1 1 /* $NetBSD: af_inet6.c,v 1.5.16.1 2008/02/22 02:53:32 keiichi Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: af_inet6.c,v 1.5.16.1 2008/02/22 02:53:32 keiichi Exp $");
35 #endif /* not lint */
36
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netinet/in_var.h>
44 #include <netinet6/nd6.h>
45
46 #include <err.h>
47 #include <errno.h>
48 #include <ifaddrs.h>
49 #include <netdb.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <util.h>
54
55 #include "extern.h"
56 #include "af_inet6.h"
57
58 static struct in6_ifreq ifr6;
59
60 struct in6_ifreq in6_ridreq;
61 struct in6_aliasreq in6_addreq;
62
63 static char *
64 sec2str(time_t total)
65 {
66 static char result[256];
67 int days, hours, mins, secs;
68 int first = 1;
69 char *p = result;
70 char *end = &result[sizeof(result)];
71 int n;
72
73 if (0) { /*XXX*/
74 days = total / 3600 / 24;
75 hours = (total / 3600) % 24;
76 mins = (total / 60) % 60;
77 secs = total % 60;
78
79 if (days) {
80 first = 0;
81 n = snprintf(p, end - p, "%dd", days);
82 if (n < 0 || n >= end - p)
83 return(result);
84 p += n;
85 }
86 if (!first || hours) {
87 first = 0;
88 n = snprintf(p, end - p, "%dh", hours);
89 if (n < 0 || n >= end - p)
90 return(result);
91 p += n;
92 }
93 if (!first || mins) {
94 first = 0;
95 n = snprintf(p, end - p, "%dm", mins);
96 if (n < 0 || n >= end - p)
97 return(result);
98 p += n;
99 }
100 snprintf(p, end - p, "%ds", secs);
101 } else
102 snprintf(p, end - p, "%lu", (u_long)total);
103
104 return(result);
105 }
106
107 static int
108 prefix(void *val, int size)
109 {
110 u_char *pname = (u_char *)val;
111 int byte, bit, plen = 0;
112
113 for (byte = 0; byte < size; byte++, plen += 8)
114 if (pname[byte] != 0xff)
115 break;
116 if (byte == size)
117 return (plen);
118 for (bit = 7; bit != 0; bit--, plen++)
119 if (!(pname[byte] & (1 << bit)))
120 break;
121 for (; bit != 0; bit--)
122 if (pname[byte] & (1 << bit))
123 return(0);
124 byte++;
125 for (; byte < size; byte++)
126 if (pname[byte])
127 return(0);
128 return (plen);
129 }
130
131 void
132 setia6flags(const char *vname, int value)
133 {
134
135 if (value < 0) {
136 value = -value;
137 in6_addreq.ifra_flags &= ~value;
138 } else
139 in6_addreq.ifra_flags |= value;
140 }
141
142 void
143 setia6pltime(const char *val, int d)
144 {
145
146 setia6lifetime("pltime", val);
147 }
148
149 void
150 setia6vltime(const char *val, int d)
151 {
152
153 setia6lifetime("vltime", val);
154 }
155
156 void
157 setia6lifetime(const char *cmd, const char *val)
158 {
159 time_t newval, t;
160 char *ep;
161
162 t = time(NULL);
163 newval = (time_t)strtoul(val, &ep, 0);
164 if (val == ep)
165 errx(EXIT_FAILURE, "invalid %s", cmd);
166 if (afp->af_af != AF_INET6)
167 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
168 if (strcmp(cmd, "vltime") == 0) {
169 in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
170 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
171 } else if (strcmp(cmd, "pltime") == 0) {
172 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
173 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
174 }
175 }
176
177 void
178 setia6eui64(const char *cmd, int val)
179 {
180 struct ifaddrs *ifap, *ifa;
181 const struct sockaddr_in6 *sin6 = NULL;
182 const struct in6_addr *lladdr = NULL;
183 struct in6_addr *in6;
184
185 if (afp->af_af != AF_INET6)
186 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
187 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
188 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
189 errx(EXIT_FAILURE, "interface index is already filled");
190 if (getifaddrs(&ifap) != 0)
191 err(EXIT_FAILURE, "getifaddrs");
192 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
193 if (ifa->ifa_addr->sa_family == AF_INET6 &&
194 strcmp(ifa->ifa_name, name) == 0) {
195 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
196 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
197 lladdr = &sin6->sin6_addr;
198 break;
199 }
200 }
201 }
202 if (!lladdr)
203 errx(EXIT_FAILURE, "could not determine link local address");
204
205 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
206
207 freeifaddrs(ifap);
208 }
209
210 void
211 in6_fillscopeid(struct sockaddr_in6 *sin6)
212 {
213 #if defined(__KAME__) && defined(KAME_SCOPEID)
214 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
215 sin6->sin6_scope_id =
216 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
217 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
218 }
219 #endif
220 }
221
222 /* XXX not really an alias */
223 void
224 in6_alias(struct in6_ifreq *creq)
225 {
226 struct sockaddr_in6 *sin6;
227 char hbuf[NI_MAXHOST];
228 u_int32_t scopeid;
229 const int niflag = NI_NUMERICHOST;
230
231 /* Get the non-alias address for this interface. */
232 getsock(AF_INET6);
233 if (s < 0) {
234 if (errno == EAFNOSUPPORT)
235 return;
236 err(EXIT_FAILURE, "socket");
237 }
238
239 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
240
241 in6_fillscopeid(sin6);
242 scopeid = sin6->sin6_scope_id;
243 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
244 hbuf, sizeof(hbuf), NULL, 0, niflag))
245 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
246 printf("\tinet6 %s", hbuf);
247
248 if (flags & IFF_POINTOPOINT) {
249 (void) memset(&ifr6, 0, sizeof(ifr6));
250 estrlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
251 ifr6.ifr_addr = creq->ifr_addr;
252 if (ioctl(s, SIOCGIFDSTADDR_IN6, &ifr6) == -1) {
253 if (errno != EADDRNOTAVAIL)
254 warn("SIOCGIFDSTADDR_IN6");
255 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
256 ifr6.ifr_addr.sin6_family = AF_INET6;
257 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
258 }
259 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
260 in6_fillscopeid(sin6);
261 hbuf[0] = '\0';
262 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
263 hbuf, sizeof(hbuf), NULL, 0, niflag))
264 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
265 printf(" -> %s", hbuf);
266 }
267
268 (void) memset(&ifr6, 0, sizeof(ifr6));
269 estrlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
270 ifr6.ifr_addr = creq->ifr_addr;
271 if (ioctl(s, SIOCGIFNETMASK_IN6, &ifr6) == -1) {
272 if (errno != EADDRNOTAVAIL)
273 warn("SIOCGIFNETMASK_IN6");
274 } else {
275 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
276 printf(" prefixlen %d", prefix(&sin6->sin6_addr,
277 sizeof(struct in6_addr)));
278 }
279
280 (void) memset(&ifr6, 0, sizeof(ifr6));
281 estrlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
282 ifr6.ifr_addr = creq->ifr_addr;
283 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
284 if (errno != EADDRNOTAVAIL)
285 warn("SIOCGIFAFLAG_IN6");
286 } else {
287 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
288 printf(" anycast");
289 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
290 printf(" tentative");
291 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
292 printf(" duplicated");
293 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
294 printf(" detached");
295 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
296 printf(" deprecated");
297 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_HOME)
298 printf(" home");
299 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEREGISTERING)
300 printf(" deregistering");
301 }
302
303 if (scopeid)
304 printf(" scopeid 0x%x", scopeid);
305
306 if (Lflag) {
307 struct in6_addrlifetime *lifetime;
308 (void) memset(&ifr6, 0, sizeof(ifr6));
309 estrlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
310 ifr6.ifr_addr = creq->ifr_addr;
311 lifetime = &ifr6.ifr_ifru.ifru_lifetime;
312 if (ioctl(s, SIOCGIFALIFETIME_IN6, &ifr6) == -1) {
313 if (errno != EADDRNOTAVAIL)
314 warn("SIOCGIFALIFETIME_IN6");
315 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
316 time_t t = time(NULL);
317 printf(" pltime ");
318 if (lifetime->ia6t_preferred) {
319 printf("%s", lifetime->ia6t_preferred < t
320 ? "0"
321 : sec2str(lifetime->ia6t_preferred - t));
322 } else
323 printf("infty");
324
325 printf(" vltime ");
326 if (lifetime->ia6t_expire) {
327 printf("%s", lifetime->ia6t_expire < t
328 ? "0"
329 : sec2str(lifetime->ia6t_expire - t));
330 } else
331 printf("infty");
332 }
333 }
334
335 printf("\n");
336 }
337
338 void
339 in6_status(int force)
340 {
341 struct ifaddrs *ifap, *ifa;
342 struct in6_ifreq isifr;
343
344 if (getifaddrs(&ifap) != 0)
345 err(EXIT_FAILURE, "getifaddrs");
346 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
347 if (strcmp(name, ifa->ifa_name) != 0)
348 continue;
349 if (ifa->ifa_addr->sa_family != AF_INET6)
350 continue;
351 if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len)
352 continue;
353
354 memset(&isifr, 0, sizeof(isifr));
355 estrlcpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name));
356 memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
357 in6_alias(&isifr);
358 }
359 freeifaddrs(ifap);
360 }
361
362 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
363 struct sockaddr_in6 *sin6tab[] = {
364 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
365 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
366
367 void
368 in6_getaddr(const char *str, int which)
369 {
370 #if defined(__KAME__) && defined(KAME_SCOPEID)
371 struct sockaddr_in6 *sin6 = sin6tab[which];
372 struct addrinfo hints, *res;
373 int error;
374 char *slash = NULL;
375
376 if (which == ADDR) {
377 if ((slash = strrchr(str, '/')) != NULL)
378 *slash = '\0';
379 }
380
381 memset(&hints, 0, sizeof(hints));
382 hints.ai_family = AF_INET6;
383 hints.ai_socktype = SOCK_DGRAM;
384 #if 0 /* in_getaddr() allows FQDN */
385 hints.ai_flags = AI_NUMERICHOST;
386 #endif
387 error = getaddrinfo(str, "0", &hints, &res);
388 if (error && slash) {
389 /* try again treating the '/' as part of the name */
390 *slash = '/';
391 slash = NULL;
392 error = getaddrinfo(str, "0", &hints, &res);
393 }
394 if (error)
395 errx(EXIT_FAILURE, "%s: %s", str, gai_strerror(error));
396 if (res->ai_next)
397 errx(EXIT_FAILURE, "%s: resolved to multiple addresses", str);
398 if (res->ai_addrlen != sizeof(struct sockaddr_in6))
399 errx(EXIT_FAILURE, "%s: bad value", str);
400 memcpy(sin6, res->ai_addr, res->ai_addrlen);
401 freeaddrinfo(res);
402 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
403 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
404 htons(sin6->sin6_scope_id);
405 sin6->sin6_scope_id = 0;
406 }
407 if (slash) {
408 in6_getprefix(slash + 1, MASK);
409 explicit_prefix = 1;
410 }
411 #else
412 struct sockaddr_in6 *gasin = sin6tab[which];
413
414 gasin->sin6_len = sizeof(*gasin);
415 if (which != MASK)
416 gasin->sin6_family = AF_INET6;
417
418 if (which == ADDR) {
419 char *p = NULL;
420 if((p = strrchr(str, '/')) != NULL) {
421 *p = '\0';
422 in6_getprefix(p + 1, MASK);
423 explicit_prefix = 1;
424 }
425 }
426
427 if (inet_pton(AF_INET6, str, &gasin->sin6_addr) != 1)
428 errx(EXIT_FAILURE, "%s: bad value", str);
429 #endif
430 }
431
432 void
433 in6_getprefix(const char *plen, int which)
434 {
435 struct sockaddr_in6 *gpsin = sin6tab[which];
436 u_char *cp;
437 int len = strtol(plen, (char **)NULL, 10);
438
439 if ((len < 0) || (len > 128))
440 errx(EXIT_FAILURE, "%s: bad value", plen);
441 gpsin->sin6_len = sizeof(*gpsin);
442 if (which != MASK)
443 gpsin->sin6_family = AF_INET6;
444 if ((len == 0) || (len == 128)) {
445 memset(&gpsin->sin6_addr, 0xff, sizeof(struct in6_addr));
446 return;
447 }
448 memset((void *)&gpsin->sin6_addr, 0x00, sizeof(gpsin->sin6_addr));
449 for (cp = (u_char *)&gpsin->sin6_addr; len > 7; len -= 8)
450 *cp++ = 0xff;
451 if (len)
452 *cp = 0xff << (8 - len);
453 }
454
455 void
456 in6_init(void)
457 {
458
459 in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
460 in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
461 }
462