1 1.60 tnn /* $NetBSD: ndp.c,v 1.60 2023/08/18 13:07:38 tnn Exp $ */ 2 1.34 rpaulo /* $KAME: ndp.c,v 1.121 2005/07/13 11:30:13 keiichi Exp $ */ 3 1.9 itojun 4 1.1 itojun /* 5 1.1 itojun * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 6 1.1 itojun * All rights reserved. 7 1.9 itojun * 8 1.1 itojun * Redistribution and use in source and binary forms, with or without 9 1.1 itojun * modification, are permitted provided that the following conditions 10 1.1 itojun * are met: 11 1.1 itojun * 1. Redistributions of source code must retain the above copyright 12 1.1 itojun * notice, this list of conditions and the following disclaimer. 13 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 itojun * notice, this list of conditions and the following disclaimer in the 15 1.1 itojun * documentation and/or other materials provided with the distribution. 16 1.1 itojun * 3. Neither the name of the project nor the names of its contributors 17 1.1 itojun * may be used to endorse or promote products derived from this software 18 1.1 itojun * without specific prior written permission. 19 1.9 itojun * 20 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 itojun * SUCH DAMAGE. 31 1.1 itojun */ 32 1.1 itojun /* 33 1.1 itojun * Copyright (c) 1984, 1993 34 1.1 itojun * The Regents of the University of California. All rights reserved. 35 1.1 itojun * 36 1.1 itojun * This code is derived from software contributed to Berkeley by 37 1.1 itojun * Sun Microsystems, Inc. 38 1.1 itojun * 39 1.1 itojun * Redistribution and use in source and binary forms, with or without 40 1.1 itojun * modification, are permitted provided that the following conditions 41 1.1 itojun * are met: 42 1.1 itojun * 1. Redistributions of source code must retain the above copyright 43 1.1 itojun * notice, this list of conditions and the following disclaimer. 44 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 itojun * notice, this list of conditions and the following disclaimer in the 46 1.1 itojun * documentation and/or other materials provided with the distribution. 47 1.29 agc * 3. Neither the name of the University nor the names of its contributors 48 1.1 itojun * may be used to endorse or promote products derived from this software 49 1.1 itojun * without specific prior written permission. 50 1.1 itojun * 51 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 1.1 itojun * SUCH DAMAGE. 62 1.1 itojun */ 63 1.1 itojun 64 1.1 itojun /* 65 1.60 tnn * Copyright (c) 1997 66 1.60 tnn * The Regents of the University of California. All rights reserved. 67 1.60 tnn * 68 1.60 tnn * Redistribution and use in source and binary forms, with or without 69 1.60 tnn * modification, are permitted provided that: (1) source code distributions 70 1.60 tnn * retain the above copyright notice and this paragraph in its entirety, (2) 71 1.60 tnn * distributions including binary code include the above copyright notice and 72 1.60 tnn * this paragraph in its entirety in the documentation or other materials 73 1.60 tnn * provided with the distribution, and (3) all advertising materials mentioning 74 1.60 tnn * features or use of this software display the following acknowledgement: 75 1.60 tnn * ``This product includes software developed by the University of California, 76 1.60 tnn * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 77 1.60 tnn * the University nor the names of its contributors may be used to endorse 78 1.60 tnn * or promote products derived from this software without specific prior 79 1.60 tnn * written permission. 80 1.60 tnn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 81 1.60 tnn * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 82 1.60 tnn * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 83 1.60 tnn */ 84 1.60 tnn 85 1.60 tnn /* 86 1.1 itojun * Based on: 87 1.1 itojun * "@(#) Copyright (c) 1984, 1993\n\ 88 1.1 itojun * The Regents of the University of California. All rights reserved.\n"; 89 1.1 itojun * 90 1.1 itojun * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 91 1.1 itojun */ 92 1.1 itojun 93 1.1 itojun /* 94 1.1 itojun * ndp - display, set, delete and flush neighbor cache 95 1.1 itojun */ 96 1.1 itojun 97 1.1 itojun 98 1.1 itojun #include <sys/param.h> 99 1.1 itojun #include <sys/file.h> 100 1.1 itojun #include <sys/ioctl.h> 101 1.1 itojun #include <sys/socket.h> 102 1.1 itojun #include <sys/sysctl.h> 103 1.1 itojun #include <sys/time.h> 104 1.1 itojun 105 1.1 itojun #include <net/if.h> 106 1.1 itojun #include <net/if_dl.h> 107 1.1 itojun #include <net/if_types.h> 108 1.1 itojun #include <net/route.h> 109 1.1 itojun 110 1.1 itojun #include <netinet/in.h> 111 1.1 itojun 112 1.1 itojun #include <netinet/icmp6.h> 113 1.1 itojun #include <netinet6/in6_var.h> 114 1.1 itojun #include <netinet6/nd6.h> 115 1.1 itojun 116 1.1 itojun #include <arpa/inet.h> 117 1.1 itojun 118 1.1 itojun #include <netdb.h> 119 1.1 itojun #include <errno.h> 120 1.1 itojun #include <nlist.h> 121 1.1 itojun #include <stdio.h> 122 1.1 itojun #include <string.h> 123 1.1 itojun #include <paths.h> 124 1.1 itojun #include <err.h> 125 1.1 itojun #include <stdlib.h> 126 1.1 itojun #include <fcntl.h> 127 1.1 itojun #include <unistd.h> 128 1.45 ozaki 129 1.45 ozaki #include "prog_ops.h" 130 1.1 itojun 131 1.19 itojun static pid_t pid; 132 1.1 itojun static int nflag; 133 1.1 itojun static int tflag; 134 1.1 itojun static int32_t thiszone; /* time difference with gmt */ 135 1.35 christos static int my_s = -1; 136 1.35 christos static unsigned int repeat = 0; 137 1.1 itojun 138 1.35 christos 139 1.35 christos static char host_buf[NI_MAXHOST]; /* getnameinfo() */ 140 1.35 christos static char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 141 1.35 christos 142 1.35 christos static void getsocket(void); 143 1.35 christos static int set(int, char **); 144 1.35 christos static void get(char *); 145 1.50 ozaki static int delete(struct rt_msghdr *, char *); 146 1.50 ozaki static void delete_one(char *); 147 1.50 ozaki static void do_foreach(struct in6_addr *, char *, int); 148 1.35 christos static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, unsigned int, int); 149 1.35 christos static char *ether_str(struct sockaddr_dl *); 150 1.35 christos static int ndp_ether_aton(char *, u_char *); 151 1.40 joerg __dead static void usage(void); 152 1.50 ozaki static int rtmsg(int, struct rt_msghdr *); 153 1.35 christos static void ifinfo(char *, int, char **); 154 1.35 christos static const char *sec2str(time_t); 155 1.35 christos static char *ether_str(struct sockaddr_dl *); 156 1.35 christos static void ts_print(const struct timeval *); 157 1.60 tnn static int32_t gmt2local(time_t t); 158 1.1 itojun 159 1.50 ozaki #define NDP_F_CLEAR 1 160 1.50 ozaki #define NDP_F_DELETE 2 161 1.50 ozaki 162 1.35 christos static int mode = 0; 163 1.35 christos static char *arg = NULL; 164 1.22 itojun 165 1.1 itojun int 166 1.35 christos main(int argc, char **argv) 167 1.1 itojun { 168 1.1 itojun int ch; 169 1.1 itojun 170 1.56 roy while ((ch = getopt(argc, argv, "acd:f:i:nstA:")) != -1) 171 1.22 itojun switch (ch) { 172 1.1 itojun case 'a': 173 1.1 itojun case 'c': 174 1.22 itojun case 's': 175 1.1 itojun case 'd': 176 1.22 itojun case 'f': 177 1.1 itojun case 'i' : 178 1.22 itojun if (mode) { 179 1.1 itojun usage(); 180 1.22 itojun /*NOTREACHED*/ 181 1.22 itojun } 182 1.22 itojun mode = ch; 183 1.22 itojun arg = optarg; 184 1.22 itojun break; 185 1.1 itojun case 'n': 186 1.1 itojun nflag = 1; 187 1.1 itojun break; 188 1.1 itojun case 't': 189 1.1 itojun tflag = 1; 190 1.1 itojun break; 191 1.1 itojun case 'A': 192 1.22 itojun if (mode) { 193 1.22 itojun usage(); 194 1.22 itojun /*NOTREACHED*/ 195 1.22 itojun } 196 1.22 itojun mode = 'a'; 197 1.1 itojun repeat = atoi(optarg); 198 1.1 itojun break; 199 1.1 itojun default: 200 1.1 itojun usage(); 201 1.1 itojun } 202 1.1 itojun 203 1.1 itojun argc -= optind; 204 1.1 itojun argv += optind; 205 1.1 itojun 206 1.45 ozaki if (prog_init && prog_init() == -1) 207 1.45 ozaki err(1, "init failed"); 208 1.45 ozaki 209 1.45 ozaki pid = prog_getpid(); 210 1.45 ozaki thiszone = gmt2local(0L); 211 1.45 ozaki 212 1.22 itojun switch (mode) { 213 1.22 itojun case 'a': 214 1.22 itojun case 'c': 215 1.22 itojun if (argc != 0) { 216 1.22 itojun usage(); 217 1.22 itojun /*NOTREACHED*/ 218 1.22 itojun } 219 1.50 ozaki do_foreach(0, NULL, mode == 'c' ? NDP_F_CLEAR : 0); 220 1.22 itojun break; 221 1.22 itojun case 'd': 222 1.22 itojun if (argc != 0) { 223 1.22 itojun usage(); 224 1.22 itojun /*NOTREACHED*/ 225 1.22 itojun } 226 1.50 ozaki delete_one(arg); 227 1.22 itojun break; 228 1.22 itojun case 'i': 229 1.22 itojun ifinfo(arg, argc, argv); 230 1.22 itojun break; 231 1.22 itojun case 's': 232 1.1 itojun if (argc < 2 || argc > 4) 233 1.1 itojun usage(); 234 1.35 christos return(set(argc, argv) ? 1 : 0); 235 1.22 itojun case 0: 236 1.22 itojun if (argc != 1) { 237 1.22 itojun usage(); 238 1.22 itojun /*NOTREACHED*/ 239 1.22 itojun } 240 1.22 itojun get(argv[0]); 241 1.22 itojun break; 242 1.1 itojun } 243 1.35 christos return(0); 244 1.1 itojun } 245 1.1 itojun 246 1.35 christos static void 247 1.46 christos makeaddr(struct sockaddr_in6 *mysin, const void *resp) 248 1.46 christos { 249 1.46 christos const struct sockaddr_in6 *res = resp; 250 1.46 christos mysin->sin6_addr = res->sin6_addr; 251 1.46 christos mysin->sin6_scope_id = res->sin6_scope_id; 252 1.46 christos inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL); 253 1.46 christos } 254 1.46 christos 255 1.46 christos static void 256 1.35 christos getsocket(void) 257 1.1 itojun { 258 1.35 christos if (my_s < 0) { 259 1.45 ozaki my_s = prog_socket(PF_ROUTE, SOCK_RAW, 0); 260 1.35 christos if (my_s < 0) 261 1.28 itojun err(1, "socket"); 262 1.1 itojun } 263 1.1 itojun } 264 1.1 itojun 265 1.35 christos #ifdef notdef 266 1.36 christos static struct sockaddr_in6 so_mask = { 267 1.36 christos .sin6_len = sizeof(so_mask), 268 1.36 christos .sin6_family = AF_INET6 269 1.36 christos }; 270 1.35 christos #endif 271 1.36 christos static struct sockaddr_in6 blank_sin = { 272 1.36 christos .sin6_len = sizeof(blank_sin), 273 1.36 christos .sin6_family = AF_INET6 274 1.36 christos }; 275 1.36 christos static struct sockaddr_in6 sin_m; 276 1.36 christos static struct sockaddr_dl blank_sdl = { 277 1.36 christos .sdl_len = sizeof(blank_sdl), 278 1.36 christos .sdl_family = AF_LINK, 279 1.36 christos }; 280 1.36 christos static struct sockaddr_dl sdl_m; 281 1.36 christos static int expire_time, flags, found_entry; 282 1.36 christos static struct { 283 1.1 itojun struct rt_msghdr m_rtm; 284 1.1 itojun char m_space[512]; 285 1.36 christos } m_rtmsg; 286 1.1 itojun 287 1.1 itojun /* 288 1.1 itojun * Set an individual neighbor cache entry 289 1.1 itojun */ 290 1.35 christos static int 291 1.35 christos set(int argc, char **argv) 292 1.1 itojun { 293 1.35 christos register struct sockaddr_in6 *mysin = &sin_m; 294 1.1 itojun register struct sockaddr_dl *sdl; 295 1.1 itojun register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 296 1.1 itojun struct addrinfo hints, *res; 297 1.1 itojun int gai_error; 298 1.1 itojun u_char *ea; 299 1.1 itojun char *host = argv[0], *eaddr = argv[1]; 300 1.1 itojun 301 1.1 itojun getsocket(); 302 1.1 itojun argc -= 2; 303 1.1 itojun argv += 2; 304 1.1 itojun sdl_m = blank_sdl; 305 1.1 itojun sin_m = blank_sin; 306 1.1 itojun 307 1.35 christos (void)memset(&hints, 0, sizeof(hints)); 308 1.1 itojun hints.ai_family = AF_INET6; 309 1.1 itojun gai_error = getaddrinfo(host, NULL, &hints, &res); 310 1.1 itojun if (gai_error) { 311 1.44 christos warnx("%s: %s", host, gai_strerror(gai_error)); 312 1.1 itojun return 1; 313 1.1 itojun } 314 1.46 christos makeaddr(mysin, res->ai_addr); 315 1.51 christos freeaddrinfo(res); 316 1.1 itojun ea = (u_char *)LLADDR(&sdl_m); 317 1.1 itojun if (ndp_ether_aton(eaddr, ea) == 0) 318 1.1 itojun sdl_m.sdl_alen = 6; 319 1.1 itojun flags = expire_time = 0; 320 1.1 itojun while (argc-- > 0) { 321 1.1 itojun if (strncmp(argv[0], "temp", 4) == 0) { 322 1.35 christos struct timeval tim; 323 1.21 itojun 324 1.35 christos (void)gettimeofday(&tim, 0); 325 1.35 christos expire_time = tim.tv_sec + 20 * 60; 326 1.6 itojun } else if (strncmp(argv[0], "proxy", 5) == 0) 327 1.6 itojun flags |= RTF_ANNOUNCE; 328 1.1 itojun argv++; 329 1.1 itojun } 330 1.50 ozaki if (rtmsg(RTM_GET, NULL) < 0) { 331 1.16 itojun errx(1, "RTM_GET(%s) failed", host); 332 1.16 itojun /* NOTREACHED */ 333 1.1 itojun } 334 1.35 christos mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 335 1.39 drochner sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + (char *)(void *)mysin); 336 1.35 christos if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { 337 1.1 itojun if (sdl->sdl_family == AF_LINK && 338 1.22 itojun !(rtm->rtm_flags & RTF_GATEWAY)) { 339 1.22 itojun switch (sdl->sdl_type) { 340 1.22 itojun case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 341 1.22 itojun case IFT_ISO88024: case IFT_ISO88025: 342 1.22 itojun goto overwrite; 343 1.22 itojun } 344 1.1 itojun } 345 1.9 itojun /* 346 1.9 itojun * IPv4 arp command retries with sin_other = SIN_PROXY here. 347 1.9 itojun */ 348 1.35 christos (void)fprintf(stderr, "set: cannot configure a new entry\n"); 349 1.9 itojun return 1; 350 1.1 itojun } 351 1.9 itojun 352 1.1 itojun overwrite: 353 1.1 itojun if (sdl->sdl_family != AF_LINK) { 354 1.35 christos warnx("cannot intuit interface index and type for %s", host); 355 1.1 itojun return (1); 356 1.1 itojun } 357 1.1 itojun sdl_m.sdl_type = sdl->sdl_type; 358 1.1 itojun sdl_m.sdl_index = sdl->sdl_index; 359 1.50 ozaki return (rtmsg(RTM_ADD, NULL)); 360 1.1 itojun } 361 1.1 itojun 362 1.1 itojun /* 363 1.1 itojun * Display an individual neighbor cache entry 364 1.1 itojun */ 365 1.35 christos static void 366 1.35 christos get(char *host) 367 1.1 itojun { 368 1.35 christos struct sockaddr_in6 *mysin = &sin_m; 369 1.1 itojun struct addrinfo hints, *res; 370 1.1 itojun int gai_error; 371 1.1 itojun 372 1.1 itojun sin_m = blank_sin; 373 1.35 christos (void)memset(&hints, 0, sizeof(hints)); 374 1.1 itojun hints.ai_family = AF_INET6; 375 1.1 itojun gai_error = getaddrinfo(host, NULL, &hints, &res); 376 1.1 itojun if (gai_error) { 377 1.44 christos warnx("%s: %s", host, gai_strerror(gai_error)); 378 1.1 itojun return; 379 1.1 itojun } 380 1.46 christos makeaddr(mysin, res->ai_addr); 381 1.51 christos freeaddrinfo(res); 382 1.50 ozaki do_foreach(&mysin->sin6_addr, host, 0); 383 1.1 itojun if (found_entry == 0) { 384 1.35 christos (void)getnameinfo((struct sockaddr *)(void *)mysin, 385 1.35 christos (socklen_t)mysin->sin6_len, 386 1.35 christos host_buf, sizeof(host_buf), NULL ,0, 387 1.21 itojun (nflag ? NI_NUMERICHOST : 0)); 388 1.35 christos errx(1, "%s (%s) -- no entry", host, host_buf); 389 1.1 itojun } 390 1.1 itojun } 391 1.1 itojun 392 1.50 ozaki static void 393 1.50 ozaki delete_one(char *host) 394 1.1 itojun { 395 1.35 christos struct sockaddr_in6 *mysin = &sin_m; 396 1.1 itojun struct addrinfo hints, *res; 397 1.1 itojun int gai_error; 398 1.1 itojun 399 1.1 itojun sin_m = blank_sin; 400 1.50 ozaki (void)memset(&hints, 0, sizeof(hints)); 401 1.1 itojun hints.ai_family = AF_INET6; 402 1.1 itojun gai_error = getaddrinfo(host, NULL, &hints, &res); 403 1.1 itojun if (gai_error) { 404 1.44 christos warnx("%s: %s", host, gai_strerror(gai_error)); 405 1.50 ozaki return; 406 1.1 itojun } 407 1.46 christos makeaddr(mysin, res->ai_addr); 408 1.51 christos freeaddrinfo(res); 409 1.50 ozaki do_foreach(&mysin->sin6_addr, host, NDP_F_DELETE); 410 1.50 ozaki } 411 1.50 ozaki 412 1.50 ozaki /* 413 1.50 ozaki * Delete a neighbor cache entry 414 1.50 ozaki */ 415 1.50 ozaki static int 416 1.50 ozaki delete(struct rt_msghdr *rtm, char *host) 417 1.50 ozaki { 418 1.53 nonaka char delete_host_buf[NI_MAXHOST]; 419 1.50 ozaki struct sockaddr_in6 *mysin = &sin_m; 420 1.50 ozaki struct sockaddr_dl *sdl; 421 1.50 ozaki 422 1.50 ozaki getsocket(); 423 1.35 christos mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 424 1.39 drochner sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + 425 1.35 christos (char *)(void *)mysin); 426 1.8 itojun 427 1.1 itojun if (sdl->sdl_family != AF_LINK) { 428 1.35 christos (void)printf("cannot locate %s\n", host); 429 1.1 itojun return (1); 430 1.1 itojun } 431 1.50 ozaki if (rtmsg(RTM_DELETE, rtm) == 0) { 432 1.35 christos struct sockaddr_in6 s6 = *mysin; /* XXX: for safety */ 433 1.11 itojun 434 1.54 nonaka s6.sin6_scope_id = 0; 435 1.54 nonaka inet6_putscopeid(&s6, INET6_IS_ADDR_LINKLOCAL); 436 1.35 christos (void)getnameinfo((struct sockaddr *)(void *)&s6, 437 1.53 nonaka (socklen_t)s6.sin6_len, delete_host_buf, 438 1.53 nonaka sizeof(delete_host_buf), NULL, 0, 439 1.21 itojun (nflag ? NI_NUMERICHOST : 0)); 440 1.53 nonaka (void)printf("%s (%s) deleted\n", host, delete_host_buf); 441 1.4 itojun } 442 1.4 itojun 443 1.1 itojun return 0; 444 1.1 itojun } 445 1.1 itojun 446 1.48 christos #define W_ADDR (8 * 4 + 7) 447 1.13 itojun #define W_LL 17 448 1.13 itojun #define W_IF 6 449 1.13 itojun 450 1.1 itojun /* 451 1.50 ozaki * Iterate on neighbor caches and do 452 1.50 ozaki * - dump all caches, 453 1.50 ozaki * - clear all caches (NDP_F_CLEAR) or 454 1.50 ozaki * - remove matched caches (NDP_F_DELETE) 455 1.1 itojun */ 456 1.35 christos static void 457 1.50 ozaki do_foreach(struct in6_addr *addr, char *host, int _flags) 458 1.1 itojun { 459 1.1 itojun int mib[6]; 460 1.1 itojun size_t needed; 461 1.4 itojun char *lim, *buf, *next; 462 1.1 itojun struct rt_msghdr *rtm; 463 1.35 christos struct sockaddr_in6 *mysin; 464 1.1 itojun struct sockaddr_dl *sdl; 465 1.1 itojun struct in6_nbrinfo *nbi; 466 1.35 christos struct timeval tim; 467 1.4 itojun int addrwidth; 468 1.13 itojun int llwidth; 469 1.13 itojun int ifwidth; 470 1.48 christos char flgbuf[8], *fl; 471 1.35 christos const char *ifname; 472 1.50 ozaki int cflag = _flags == NDP_F_CLEAR; 473 1.50 ozaki int dflag = _flags == NDP_F_DELETE; 474 1.1 itojun 475 1.1 itojun /* Print header */ 476 1.11 itojun if (!tflag && !cflag) 477 1.48 christos (void)printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %2s\n", 478 1.13 itojun W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 479 1.48 christos W_IF, W_IF, "Netif", "Expire", "S", "Fl"); 480 1.1 itojun 481 1.1 itojun again:; 482 1.1 itojun mib[0] = CTL_NET; 483 1.1 itojun mib[1] = PF_ROUTE; 484 1.1 itojun mib[2] = 0; 485 1.1 itojun mib[3] = AF_INET6; 486 1.1 itojun mib[4] = NET_RT_FLAGS; 487 1.50 ozaki mib[5] = RTF_LLDATA; 488 1.45 ozaki if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 489 1.3 itojun err(1, "sysctl(PF_ROUTE estimate)"); 490 1.3 itojun if (needed > 0) { 491 1.3 itojun if ((buf = malloc(needed)) == NULL) 492 1.28 itojun err(1, "malloc"); 493 1.50 ozaki if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 494 1.50 ozaki free(buf); 495 1.50 ozaki if (errno == ENOBUFS) 496 1.50 ozaki goto again; 497 1.3 itojun err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 498 1.50 ozaki } 499 1.3 itojun lim = buf + needed; 500 1.3 itojun } else 501 1.3 itojun buf = lim = NULL; 502 1.1 itojun 503 1.3 itojun for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 504 1.1 itojun int isrouter = 0, prbs = 0; 505 1.1 itojun 506 1.35 christos rtm = (struct rt_msghdr *)(void *)next; 507 1.35 christos mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 508 1.39 drochner sdl = (struct sockaddr_dl *)(void *)((char *)(void *)mysin + RT_ROUNDUP(mysin->sin6_len)); 509 1.16 itojun 510 1.16 itojun /* 511 1.16 itojun * Some OSes can produce a route that has the LINK flag but 512 1.16 itojun * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 513 1.16 itojun * and BSD/OS, where xx is not the interface identifier on 514 1.16 itojun * lo0). Such routes entry would annoy getnbrinfo() below, 515 1.16 itojun * so we skip them. 516 1.16 itojun * XXX: such routes should have the GATEWAY flag, not the 517 1.16 itojun * LINK flag. However, there is rotten routing software 518 1.16 itojun * that advertises all routes that have the GATEWAY flag. 519 1.16 itojun * Thus, KAME kernel intentionally does not set the LINK flag. 520 1.16 itojun * What is to be fixed is not ndp, but such routing software 521 1.16 itojun * (and the kernel workaround)... 522 1.16 itojun */ 523 1.16 itojun if (sdl->sdl_family != AF_LINK) 524 1.16 itojun continue; 525 1.16 itojun 526 1.19 itojun if (!(rtm->rtm_flags & RTF_HOST)) 527 1.19 itojun continue; 528 1.19 itojun 529 1.1 itojun if (addr) { 530 1.35 christos if (!IN6_ARE_ADDR_EQUAL(addr, &mysin->sin6_addr)) 531 1.1 itojun continue; 532 1.1 itojun found_entry = 1; 533 1.35 christos } else if (IN6_IS_ADDR_MULTICAST(&mysin->sin6_addr)) 534 1.1 itojun continue; 535 1.50 ozaki if (dflag) { 536 1.50 ozaki (void)delete(rtm, host_buf); 537 1.50 ozaki continue; 538 1.50 ozaki } 539 1.35 christos if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) || 540 1.35 christos IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr)) { 541 1.41 christos uint16_t scopeid = mysin->sin6_scope_id; 542 1.41 christos inet6_getscopeid(mysin, INET6_IS_ADDR_LINKLOCAL| 543 1.41 christos INET6_IS_ADDR_MC_LINKLOCAL); 544 1.41 christos if (scopeid == 0) 545 1.35 christos mysin->sin6_scope_id = sdl->sdl_index; 546 1.1 itojun } 547 1.35 christos (void)getnameinfo((struct sockaddr *)(void *)mysin, 548 1.35 christos (socklen_t)mysin->sin6_len, 549 1.35 christos host_buf, sizeof(host_buf), NULL, 0, 550 1.35 christos (nflag ? NI_NUMERICHOST : 0)); 551 1.22 itojun if (cflag) { 552 1.50 ozaki /* Restore scopeid */ 553 1.50 ozaki if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) || 554 1.50 ozaki IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr)) 555 1.50 ozaki inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL| 556 1.50 ozaki INET6_IS_ADDR_MC_LINKLOCAL); 557 1.47 ozaki if ((rtm->rtm_flags & RTF_STATIC) == 0) 558 1.50 ozaki (void)delete(rtm, host_buf); 559 1.11 itojun continue; 560 1.11 itojun } 561 1.35 christos (void)gettimeofday(&tim, 0); 562 1.1 itojun if (tflag) 563 1.35 christos ts_print(&tim); 564 1.1 itojun 565 1.13 itojun addrwidth = strlen(host_buf); 566 1.13 itojun if (addrwidth < W_ADDR) 567 1.13 itojun addrwidth = W_ADDR; 568 1.13 itojun llwidth = strlen(ether_str(sdl)); 569 1.13 itojun if (W_ADDR + W_LL - addrwidth > llwidth) 570 1.13 itojun llwidth = W_ADDR + W_LL - addrwidth; 571 1.35 christos ifname = if_indextoname((unsigned int)sdl->sdl_index, ifix_buf); 572 1.14 itojun if (!ifname) 573 1.14 itojun ifname = "?"; 574 1.14 itojun ifwidth = strlen(ifname); 575 1.13 itojun if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 576 1.13 itojun ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 577 1.13 itojun 578 1.35 christos (void)printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, 579 1.35 christos host_buf, llwidth, llwidth, ether_str(sdl), ifwidth, 580 1.35 christos ifwidth, ifname); 581 1.1 itojun 582 1.1 itojun /* Print neighbor discovery specific informations */ 583 1.35 christos nbi = getnbrinfo(&mysin->sin6_addr, 584 1.35 christos (unsigned int)sdl->sdl_index, 1); 585 1.1 itojun if (nbi) { 586 1.35 christos if (nbi->expire > tim.tv_sec) { 587 1.35 christos (void)printf(" %-9.9s", 588 1.35 christos sec2str(nbi->expire - tim.tv_sec)); 589 1.11 itojun } else if (nbi->expire == 0) 590 1.35 christos (void)printf(" %-9.9s", "permanent"); 591 1.1 itojun else 592 1.35 christos (void)printf(" %-9.9s", "expired"); 593 1.1 itojun 594 1.21 itojun switch (nbi->state) { 595 1.58 roy case ND_LLINFO_NOSTATE: 596 1.35 christos (void)printf(" N"); 597 1.1 itojun break; 598 1.58 roy case ND_LLINFO_WAITDELETE: 599 1.35 christos (void)printf(" W"); 600 1.1 itojun break; 601 1.58 roy case ND_LLINFO_INCOMPLETE: 602 1.35 christos (void)printf(" I"); 603 1.1 itojun break; 604 1.58 roy case ND_LLINFO_REACHABLE: 605 1.35 christos (void)printf(" R"); 606 1.1 itojun break; 607 1.58 roy case ND_LLINFO_STALE: 608 1.35 christos (void)printf(" S"); 609 1.1 itojun break; 610 1.58 roy case ND_LLINFO_DELAY: 611 1.35 christos (void)printf(" D"); 612 1.1 itojun break; 613 1.58 roy case ND_LLINFO_PROBE: 614 1.35 christos (void)printf(" P"); 615 1.1 itojun break; 616 1.58 roy case ND_LLINFO_UNREACHABLE: 617 1.58 roy (void)printf(" U"); 618 1.58 roy break; 619 1.19 itojun default: 620 1.35 christos (void)printf(" ?"); 621 1.1 itojun break; 622 1.1 itojun } 623 1.1 itojun 624 1.1 itojun isrouter = nbi->isrouter; 625 1.1 itojun prbs = nbi->asked; 626 1.11 itojun } else { 627 1.1 itojun warnx("failed to get neighbor information"); 628 1.35 christos (void)printf(" "); 629 1.1 itojun } 630 1.1 itojun 631 1.4 itojun /* 632 1.4 itojun * other flags. R: router, P: proxy, W: ?? 633 1.4 itojun */ 634 1.48 christos fl = flgbuf; 635 1.48 christos if (isrouter) 636 1.48 christos *fl++ = 'R'; 637 1.48 christos if (rtm->rtm_flags & RTF_ANNOUNCE) 638 1.48 christos *fl++ = 'p'; 639 1.48 christos *fl++ = '\0'; 640 1.35 christos (void)printf(" %s", flgbuf); 641 1.1 itojun 642 1.1 itojun if (prbs) 643 1.35 christos (void)printf(" %d", prbs); 644 1.1 itojun 645 1.35 christos (void)printf("\n"); 646 1.1 itojun } 647 1.12 itojun if (buf != NULL) 648 1.12 itojun free(buf); 649 1.1 itojun 650 1.1 itojun if (repeat) { 651 1.35 christos (void)printf("\n"); 652 1.35 christos (void)fflush(stdout); 653 1.35 christos (void)sleep(repeat); 654 1.1 itojun goto again; 655 1.1 itojun } 656 1.1 itojun } 657 1.1 itojun 658 1.1 itojun static struct in6_nbrinfo * 659 1.35 christos getnbrinfo(struct in6_addr *addr, unsigned int ifindex, int warning) 660 1.1 itojun { 661 1.1 itojun static struct in6_nbrinfo nbi; 662 1.1 itojun int s; 663 1.1 itojun 664 1.45 ozaki if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 665 1.1 itojun err(1, "socket"); 666 1.1 itojun 667 1.35 christos (void)memset(&nbi, 0, sizeof(nbi)); 668 1.35 christos (void)if_indextoname(ifindex, nbi.ifname); 669 1.1 itojun nbi.addr = *addr; 670 1.45 ozaki if (prog_ioctl(s, SIOCGNBRINFO_IN6, &nbi) < 0) { 671 1.4 itojun if (warning) 672 1.8 itojun warn("ioctl(SIOCGNBRINFO_IN6)"); 673 1.45 ozaki (void)prog_close(s); 674 1.1 itojun return(NULL); 675 1.1 itojun } 676 1.1 itojun 677 1.45 ozaki (void)prog_close(s); 678 1.1 itojun return(&nbi); 679 1.1 itojun } 680 1.1 itojun 681 1.1 itojun static char * 682 1.35 christos ether_str(struct sockaddr_dl *sdl) 683 1.1 itojun { 684 1.17 bjh21 static char hbuf[NI_MAXHOST]; 685 1.1 itojun 686 1.1 itojun if (sdl->sdl_alen) { 687 1.35 christos if (getnameinfo((struct sockaddr *)(void *)sdl, 688 1.35 christos (socklen_t)sdl->sdl_len, 689 1.17 bjh21 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 690 1.35 christos (void)snprintf(hbuf, sizeof(hbuf), "<invalid>"); 691 1.20 itojun } else 692 1.35 christos (void)snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 693 1.1 itojun 694 1.17 bjh21 return(hbuf); 695 1.1 itojun } 696 1.1 itojun 697 1.35 christos static int 698 1.35 christos ndp_ether_aton(char *a, u_char *n) 699 1.1 itojun { 700 1.1 itojun int i, o[6]; 701 1.1 itojun 702 1.1 itojun i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 703 1.21 itojun &o[3], &o[4], &o[5]); 704 1.1 itojun if (i != 6) { 705 1.35 christos warnx("invalid Ethernet address '%s'", a); 706 1.1 itojun return (1); 707 1.1 itojun } 708 1.24 itojun for (i = 0; i < 6; i++) 709 1.1 itojun n[i] = o[i]; 710 1.1 itojun return (0); 711 1.1 itojun } 712 1.1 itojun 713 1.35 christos static void 714 1.35 christos usage(void) 715 1.1 itojun { 716 1.35 christos const char *pn = getprogname(); 717 1.35 christos 718 1.35 christos (void)fprintf(stderr, "Usage: %s [-nt] hostname\n", pn); 719 1.35 christos (void)fprintf(stderr, 720 1.57 roy " %s [-nt] -a | -c\n", pn); 721 1.35 christos (void)fprintf(stderr, " %s [-nt] -A wait\n", pn); 722 1.35 christos (void)fprintf(stderr, " %s [-nt] -d hostname\n", pn); 723 1.35 christos (void)fprintf(stderr, " %s [-nt] -f filename\n", pn); 724 1.35 christos (void)fprintf(stderr, " %s [-nt] -i interface [flags...]\n", pn); 725 1.35 christos (void)fprintf(stderr, 726 1.35 christos " %s [-nt] -s nodename etheraddr [temp] [proxy]\n", pn); 727 1.1 itojun exit(1); 728 1.1 itojun } 729 1.1 itojun 730 1.35 christos static int 731 1.50 ozaki rtmsg(int cmd, struct rt_msghdr *_rtm) 732 1.1 itojun { 733 1.1 itojun static int seq; 734 1.50 ozaki register struct rt_msghdr *rtm = _rtm; 735 1.1 itojun register char *cp = m_rtmsg.m_space; 736 1.1 itojun register int l; 737 1.1 itojun 738 1.1 itojun errno = 0; 739 1.50 ozaki if (rtm != NULL) { 740 1.50 ozaki memcpy(&m_rtmsg, rtm, rtm->rtm_msglen); 741 1.50 ozaki rtm = &m_rtmsg.m_rtm; 742 1.1 itojun goto doit; 743 1.47 ozaki } 744 1.35 christos (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 745 1.50 ozaki rtm = &m_rtmsg.m_rtm; 746 1.1 itojun rtm->rtm_flags = flags; 747 1.1 itojun rtm->rtm_version = RTM_VERSION; 748 1.1 itojun 749 1.1 itojun switch (cmd) { 750 1.1 itojun default: 751 1.35 christos errx(1, "internal wrong cmd"); 752 1.35 christos /*NOTREACHED*/ 753 1.1 itojun case RTM_ADD: 754 1.1 itojun rtm->rtm_addrs |= RTA_GATEWAY; 755 1.19 itojun if (expire_time) { 756 1.19 itojun rtm->rtm_rmx.rmx_expire = expire_time; 757 1.19 itojun rtm->rtm_inits = RTV_EXPIRE; 758 1.19 itojun } 759 1.47 ozaki rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 760 1.35 christos #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ 761 1.6 itojun if (rtm->rtm_flags & RTF_ANNOUNCE) { 762 1.6 itojun rtm->rtm_flags &= ~RTF_HOST; 763 1.30 itojun rtm->rtm_addrs |= RTA_NETMASK; 764 1.6 itojun } 765 1.34 rpaulo #endif 766 1.47 ozaki rtm->rtm_addrs |= RTA_DST; 767 1.47 ozaki break; 768 1.1 itojun case RTM_GET: 769 1.47 ozaki rtm->rtm_flags |= RTF_LLDATA; 770 1.49 ozaki rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY; 771 1.1 itojun } 772 1.1 itojun #define NEXTADDR(w, s) \ 773 1.1 itojun if (rtm->rtm_addrs & (w)) { \ 774 1.35 christos (void)memcpy(cp, &s, sizeof(s)); \ 775 1.39 drochner RT_ADVANCE(cp, (struct sockaddr *)(void *)&s); \ 776 1.35 christos } 777 1.1 itojun 778 1.1 itojun NEXTADDR(RTA_DST, sin_m); 779 1.1 itojun NEXTADDR(RTA_GATEWAY, sdl_m); 780 1.35 christos #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ 781 1.35 christos (void)memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 782 1.1 itojun NEXTADDR(RTA_NETMASK, so_mask); 783 1.34 rpaulo #endif 784 1.1 itojun 785 1.35 christos rtm->rtm_msglen = cp - (char *)(void *)&m_rtmsg; 786 1.1 itojun doit: 787 1.1 itojun l = rtm->rtm_msglen; 788 1.1 itojun rtm->rtm_seq = ++seq; 789 1.1 itojun rtm->rtm_type = cmd; 790 1.45 ozaki if (prog_write(my_s, &m_rtmsg, (size_t)l) == -1) { 791 1.35 christos if (errno != ESRCH || cmd != RTM_DELETE) 792 1.16 itojun err(1, "writing to routing socket"); 793 1.1 itojun } 794 1.1 itojun do { 795 1.45 ozaki l = prog_read(my_s, &m_rtmsg, sizeof(m_rtmsg)); 796 1.1 itojun } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 797 1.1 itojun if (l < 0) 798 1.35 christos warn("read from routing socket"); 799 1.1 itojun return (0); 800 1.1 itojun } 801 1.1 itojun 802 1.35 christos static void 803 1.35 christos ifinfo(char *ifname, int argc, char **argv) 804 1.1 itojun { 805 1.1 itojun struct in6_ndireq nd; 806 1.8 itojun int i, s; 807 1.8 itojun u_int32_t newflags; 808 1.56 roy bool valset = false, flagset = false; 809 1.1 itojun 810 1.45 ozaki if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 811 1.16 itojun err(1, "socket"); 812 1.35 christos (void)memset(&nd, 0, sizeof(nd)); 813 1.35 christos (void)strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 814 1.45 ozaki if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) 815 1.21 itojun err(1, "ioctl(SIOCGIFINFO_IN6)"); 816 1.1 itojun #define ND nd.ndi 817 1.8 itojun newflags = ND.flags; 818 1.22 itojun for (i = 0; i < argc; i++) { 819 1.8 itojun int clear = 0; 820 1.8 itojun char *cp = argv[i]; 821 1.8 itojun 822 1.8 itojun if (*cp == '-') { 823 1.8 itojun clear = 1; 824 1.8 itojun cp++; 825 1.8 itojun } 826 1.8 itojun 827 1.8 itojun #define SETFLAG(s, f) \ 828 1.8 itojun do {\ 829 1.8 itojun if (strcmp(cp, (s)) == 0) {\ 830 1.8 itojun if (clear)\ 831 1.8 itojun newflags &= ~(f);\ 832 1.8 itojun else\ 833 1.8 itojun newflags |= (f);\ 834 1.56 roy flagset = true; \ 835 1.8 itojun }\ 836 1.59 rillig } while (0) 837 1.34 rpaulo /* 838 1.34 rpaulo * XXX: this macro is not 100% correct, in that it matches "nud" against 839 1.34 rpaulo * "nudbogus". But we just let it go since this is minor. 840 1.34 rpaulo */ 841 1.34 rpaulo #define SETVALUE(f, v) \ 842 1.34 rpaulo do { \ 843 1.34 rpaulo char *valptr; \ 844 1.34 rpaulo unsigned long newval; \ 845 1.34 rpaulo v = 0; /* unspecified */ \ 846 1.34 rpaulo if (strncmp(cp, f, strlen(f)) == 0) { \ 847 1.34 rpaulo valptr = strchr(cp, '='); \ 848 1.34 rpaulo if (valptr == NULL) \ 849 1.34 rpaulo err(1, "syntax error in %s field", (f)); \ 850 1.34 rpaulo errno = 0; \ 851 1.34 rpaulo newval = strtoul(++valptr, NULL, 0); \ 852 1.34 rpaulo if (errno) \ 853 1.34 rpaulo err(1, "syntax error in %s's value", (f)); \ 854 1.34 rpaulo v = newval; \ 855 1.56 roy valset = true; \ 856 1.34 rpaulo } \ 857 1.59 rillig } while (0) 858 1.34 rpaulo 859 1.34 rpaulo #ifdef ND6_IFF_IFDISABLED 860 1.34 rpaulo SETFLAG("disabled", ND6_IFF_IFDISABLED); 861 1.34 rpaulo #endif 862 1.8 itojun SETFLAG("nud", ND6_IFF_PERFORMNUD); 863 1.19 itojun #ifdef ND6_IFF_ACCEPT_RTADV 864 1.19 itojun SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 865 1.19 itojun #endif 866 1.38 dyoung #ifdef ND6_IFF_OVERRIDE_RTADV 867 1.38 dyoung SETFLAG("override_rtadv", ND6_IFF_OVERRIDE_RTADV); 868 1.38 dyoung #endif 869 1.43 roy #ifdef ND6_IFF_AUTO_LINKLOCAL 870 1.43 roy SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL); 871 1.43 roy #endif 872 1.19 itojun #ifdef ND6_IFF_PREFER_SOURCE 873 1.19 itojun SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE); 874 1.19 itojun #endif 875 1.34 rpaulo #ifdef ND6_IFF_DONT_SET_IFROUTE 876 1.34 rpaulo SETFLAG("dont_set_ifroute", ND6_IFF_DONT_SET_IFROUTE); 877 1.34 rpaulo #endif 878 1.34 rpaulo SETVALUE("basereachable", ND.basereachable); 879 1.34 rpaulo SETVALUE("retrans", ND.retrans); 880 1.34 rpaulo SETVALUE("curhlim", ND.chlim); 881 1.8 itojun 882 1.8 itojun ND.flags = newflags; 883 1.34 rpaulo #ifdef SIOCSIFINFO_IN6 884 1.56 roy if (valset && prog_ioctl(s, SIOCSIFINFO_IN6, &nd) < 0) 885 1.34 rpaulo err(1, "ioctl(SIOCSIFINFO_IN6)"); 886 1.56 roy #endif 887 1.56 roy if (flagset && prog_ioctl(s, SIOCSIFINFO_FLAGS, &nd) < 0) 888 1.16 itojun err(1, "ioctl(SIOCSIFINFO_FLAGS)"); 889 1.8 itojun #undef SETFLAG 890 1.34 rpaulo #undef SETVALUE 891 1.8 itojun } 892 1.8 itojun 893 1.45 ozaki if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) 894 1.34 rpaulo err(1, "ioctl(SIOCGIFINFO_IN6)"); 895 1.56 roy (void)printf("curhlim=%d", ND.chlim); 896 1.35 christos (void)printf(", basereachable=%ds%dms", 897 1.21 itojun ND.basereachable / 1000, ND.basereachable % 1000); 898 1.35 christos (void)printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 899 1.8 itojun if (ND.flags) { 900 1.35 christos (void)printf("\nFlags: "); 901 1.19 itojun if ((ND.flags & ND6_IFF_PERFORMNUD)) 902 1.35 christos (void)printf("nud "); 903 1.34 rpaulo #ifdef ND6_IFF_IFDISABLED 904 1.34 rpaulo if ((ND.flags & ND6_IFF_IFDISABLED)) 905 1.35 christos (void)printf("disabled "); 906 1.34 rpaulo #endif 907 1.43 roy #ifdef ND6_IFF_AUTO_LINKLOCAL 908 1.43 roy if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) 909 1.43 roy (void)printf("auto_linklocal "); 910 1.43 roy #endif 911 1.19 itojun #ifdef ND6_IFF_PREFER_SOURCE 912 1.19 itojun if ((ND.flags & ND6_IFF_PREFER_SOURCE)) 913 1.35 christos (void)printf("prefer_source "); 914 1.19 itojun #endif 915 1.8 itojun } 916 1.35 christos (void)putc('\n', stdout); 917 1.1 itojun #undef ND 918 1.21 itojun 919 1.45 ozaki (void)prog_close(s); 920 1.1 itojun } 921 1.1 itojun 922 1.35 christos static const char * 923 1.35 christos sec2str(time_t total) 924 1.1 itojun { 925 1.1 itojun static char result[256]; 926 1.1 itojun int days, hours, mins, secs; 927 1.1 itojun int first = 1; 928 1.1 itojun char *p = result; 929 1.19 itojun char *ep = &result[sizeof(result)]; 930 1.19 itojun int n; 931 1.1 itojun 932 1.1 itojun days = total / 3600 / 24; 933 1.1 itojun hours = (total / 3600) % 24; 934 1.1 itojun mins = (total / 60) % 60; 935 1.1 itojun secs = total % 60; 936 1.1 itojun 937 1.1 itojun if (days) { 938 1.1 itojun first = 0; 939 1.35 christos n = snprintf(p, (size_t)(ep - p), "%dd", days); 940 1.19 itojun if (n < 0 || n >= ep - p) 941 1.19 itojun return "?"; 942 1.19 itojun p += n; 943 1.1 itojun } 944 1.1 itojun if (!first || hours) { 945 1.1 itojun first = 0; 946 1.35 christos n = snprintf(p, (size_t)(ep - p), "%dh", hours); 947 1.19 itojun if (n < 0 || n >= ep - p) 948 1.19 itojun return "?"; 949 1.19 itojun p += n; 950 1.1 itojun } 951 1.1 itojun if (!first || mins) { 952 1.1 itojun first = 0; 953 1.35 christos n = snprintf(p, (size_t)(ep - p), "%dm", mins); 954 1.19 itojun if (n < 0 || n >= ep - p) 955 1.19 itojun return "?"; 956 1.19 itojun p += n; 957 1.1 itojun } 958 1.35 christos (void)snprintf(p, (size_t)(ep - p), "%ds", secs); 959 1.1 itojun 960 1.1 itojun return(result); 961 1.1 itojun } 962 1.1 itojun 963 1.1 itojun /* 964 1.1 itojun * Print the timestamp 965 1.1 itojun * from tcpdump/util.c 966 1.1 itojun */ 967 1.1 itojun static void 968 1.35 christos ts_print(const struct timeval *tvp) 969 1.1 itojun { 970 1.1 itojun int s; 971 1.1 itojun 972 1.1 itojun /* Default */ 973 1.1 itojun s = (tvp->tv_sec + thiszone) % 86400; 974 1.1 itojun (void)printf("%02d:%02d:%02d.%06u ", 975 1.1 itojun s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 976 1.1 itojun } 977 1.60 tnn 978 1.60 tnn /* 979 1.60 tnn * Returns the difference between gmt and local time in seconds. 980 1.60 tnn * Use gmtime() and localtime() to keep things simple. 981 1.60 tnn */ 982 1.60 tnn static int32_t 983 1.60 tnn gmt2local(time_t t) 984 1.60 tnn { 985 1.60 tnn int dt, dir; 986 1.60 tnn struct tm *gmt, *loc; 987 1.60 tnn struct tm sgmt; 988 1.60 tnn 989 1.60 tnn if (t == 0) 990 1.60 tnn t = time(NULL); 991 1.60 tnn gmt = &sgmt; 992 1.60 tnn *gmt = *gmtime(&t); 993 1.60 tnn loc = localtime(&t); 994 1.60 tnn dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + 995 1.60 tnn (loc->tm_min - gmt->tm_min) * 60; 996 1.60 tnn 997 1.60 tnn /* 998 1.60 tnn * If the year or julian day is different, we span 00:00 GMT 999 1.60 tnn * and must add or subtract a day. Check the year first to 1000 1.60 tnn * avoid problems when the julian day wraps. 1001 1.60 tnn */ 1002 1.60 tnn dir = loc->tm_year - gmt->tm_year; 1003 1.60 tnn if (dir == 0) 1004 1.60 tnn dir = loc->tm_yday - gmt->tm_yday; 1005 1.60 tnn dt += dir * 24 * 60 * 60; 1006 1.60 tnn 1007 1.60 tnn return (dt); 1008 1.60 tnn } 1009