Deleted Added
full compact
ndp.c (245230) ndp.c (246143)
1/* $FreeBSD: head/usr.sbin/ndp/ndp.c 245230 2013-01-09 18:18:08Z ume $ */
1/* $FreeBSD: head/usr.sbin/ndp/ndp.c 246143 2013-01-31 08:55:21Z glebius $ */
2/* $KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32/*
33 * Copyright (c) 1984, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * Sun Microsystems, Inc.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64/*
65 * Based on:
66 * "@(#) Copyright (c) 1984, 1993\n\
67 * The Regents of the University of California. All rights reserved.\n";
68 *
69 * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
70 */
71
72/*
73 * ndp - display, set, delete and flush neighbor cache
74 */
75
76
77#include <sys/param.h>
78#include <sys/file.h>
79#include <sys/ioctl.h>
80#include <sys/socket.h>
81#include <sys/sysctl.h>
82#include <sys/time.h>
83#include <sys/queue.h>
84
85#include <net/if.h>
86#include <net/if_var.h>
87#include <net/if_dl.h>
88#include <net/if_types.h>
89#include <net/route.h>
90
91#include <netinet/in.h>
92#include <netinet/if_ether.h>
93
94#include <netinet/icmp6.h>
95#include <netinet6/in6_var.h>
96#include <netinet6/nd6.h>
97
98#include <arpa/inet.h>
99
100#include <netdb.h>
101#include <errno.h>
102#include <nlist.h>
103#include <stdio.h>
104#include <string.h>
105#include <paths.h>
106#include <err.h>
107#include <stdlib.h>
108#include <fcntl.h>
109#include <unistd.h>
110#include "gmt2local.h"
111
112/* packing rule for routing socket */
113#define ROUNDUP(a) \
114 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
115#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
116
117#define NEXTADDR(w, s) \
118 if (rtm->rtm_addrs & (w)) { \
119 bcopy((char *)&s, cp, sizeof(s)); cp += SA_SIZE(&s);}
120
121
122static pid_t pid;
123static int nflag;
124static int tflag;
125static int32_t thiszone; /* time difference with gmt */
126static int s = -1;
127static int repeat = 0;
128
129char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */
130char host_buf[NI_MAXHOST]; /* getnameinfo() */
131char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
132
133int main(int, char **);
134int file(char *);
135void getsocket(void);
136int set(int, char **);
137void get(char *);
138int delete(char *);
139void dump(struct in6_addr *, int);
140static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
141static char *ether_str(struct sockaddr_dl *);
142int ndp_ether_aton(char *, u_char *);
143void usage(void);
144int rtmsg(int);
145void ifinfo(char *, int, char **);
146void rtrlist(void);
147void plist(void);
148void pfx_flush(void);
149void rtr_flush(void);
150void harmonize_rtr(void);
151#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
152static void getdefif(void);
153static void setdefif(char *);
154#endif
155static char *sec2str(time_t);
156static void ts_print(const struct timeval *);
157
158#ifdef ICMPV6CTL_ND6_DRLIST
159static char *rtpref_str[] = {
160 "medium", /* 00 */
161 "high", /* 01 */
162 "rsv", /* 10 */
163 "low" /* 11 */
164};
165#endif
166
167int mode = 0;
168char *arg = NULL;
169
170int
171main(argc, argv)
172 int argc;
173 char **argv;
174{
175 int ch;
176
177 pid = getpid();
178 thiszone = gmt2local(0);
179 while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
180 switch (ch) {
181 case 'a':
182 case 'c':
183 case 'p':
184 case 'r':
185 case 'H':
186 case 'P':
187 case 'R':
188 case 's':
189 case 'I':
190 if (mode) {
191 usage();
192 /*NOTREACHED*/
193 }
194 mode = ch;
195 arg = NULL;
196 break;
197 case 'd':
198 case 'f':
199 case 'i' :
200 if (mode) {
201 usage();
202 /*NOTREACHED*/
203 }
204 mode = ch;
205 arg = optarg;
206 break;
207 case 'n':
208 nflag = 1;
209 break;
210 case 't':
211 tflag = 1;
212 break;
213 case 'A':
214 if (mode) {
215 usage();
216 /*NOTREACHED*/
217 }
218 mode = 'a';
219 repeat = atoi(optarg);
220 if (repeat < 0) {
221 usage();
222 /*NOTREACHED*/
223 }
224 break;
225 default:
226 usage();
227 }
228
229 argc -= optind;
230 argv += optind;
231
232 switch (mode) {
233 case 'a':
234 case 'c':
235 if (argc != 0) {
236 usage();
237 /*NOTREACHED*/
238 }
239 dump(0, mode == 'c');
240 break;
241 case 'd':
242 if (argc != 0) {
243 usage();
244 /*NOTREACHED*/
245 }
246 delete(arg);
247 break;
248 case 'I':
249#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
250 if (argc > 1) {
251 usage();
252 /*NOTREACHED*/
253 } else if (argc == 1) {
254 if (strcmp(*argv, "delete") == 0 ||
255 if_nametoindex(*argv))
256 setdefif(*argv);
257 else
258 errx(1, "invalid interface %s", *argv);
259 }
260 getdefif(); /* always call it to print the result */
261 break;
262#else
263 errx(1, "not supported yet");
264 /*NOTREACHED*/
265#endif
266 case 'p':
267 if (argc != 0) {
268 usage();
269 /*NOTREACHED*/
270 }
271 plist();
272 break;
273 case 'i':
274 ifinfo(arg, argc, argv);
275 break;
276 case 'r':
277 if (argc != 0) {
278 usage();
279 /*NOTREACHED*/
280 }
281 rtrlist();
282 break;
283 case 's':
284 if (argc < 2 || argc > 4)
285 usage();
286 exit(set(argc, argv) ? 1 : 0);
287 case 'H':
288 if (argc != 0) {
289 usage();
290 /*NOTREACHED*/
291 }
292 harmonize_rtr();
293 break;
294 case 'P':
295 if (argc != 0) {
296 usage();
297 /*NOTREACHED*/
298 }
299 pfx_flush();
300 break;
301 case 'R':
302 if (argc != 0) {
303 usage();
304 /*NOTREACHED*/
305 }
306 rtr_flush();
307 break;
308 case 0:
309 if (argc != 1) {
310 usage();
311 /*NOTREACHED*/
312 }
313 get(argv[0]);
314 break;
315 }
316 exit(0);
317}
318
319/*
320 * Process a file to set standard ndp entries
321 */
322int
323file(name)
324 char *name;
325{
326 FILE *fp;
327 int i, retval;
328 char line[100], arg[5][50], *args[5];
329
330 if ((fp = fopen(name, "r")) == NULL) {
331 fprintf(stderr, "ndp: cannot open %s\n", name);
332 exit(1);
333 }
334 args[0] = &arg[0][0];
335 args[1] = &arg[1][0];
336 args[2] = &arg[2][0];
337 args[3] = &arg[3][0];
338 args[4] = &arg[4][0];
339 retval = 0;
340 while (fgets(line, sizeof(line), fp) != NULL) {
341 i = sscanf(line, "%49s %49s %49s %49s %49s",
342 arg[0], arg[1], arg[2], arg[3], arg[4]);
343 if (i < 2) {
344 fprintf(stderr, "ndp: bad line: %s\n", line);
345 retval = 1;
346 continue;
347 }
348 if (set(i, args))
349 retval = 1;
350 }
351 fclose(fp);
352 return (retval);
353}
354
355void
356getsocket()
357{
358 if (s < 0) {
359 s = socket(PF_ROUTE, SOCK_RAW, 0);
360 if (s < 0) {
361 err(1, "socket");
362 /* NOTREACHED */
363 }
364 }
365}
366
367struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
368struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
369struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
370int expire_time, flags, found_entry;
371struct {
372 struct rt_msghdr m_rtm;
373 char m_space[512];
374} m_rtmsg;
375
376/*
377 * Set an individual neighbor cache entry
378 */
379int
380set(argc, argv)
381 int argc;
382 char **argv;
383{
384 register struct sockaddr_in6 *sin = &sin_m;
385 register struct sockaddr_dl *sdl;
386 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
387 struct addrinfo hints, *res;
388 int gai_error;
389 u_char *ea;
390 char *host = argv[0], *eaddr = argv[1];
391
392 getsocket();
393 argc -= 2;
394 argv += 2;
395 sdl_m = blank_sdl;
396 sin_m = blank_sin;
397
398 bzero(&hints, sizeof(hints));
399 hints.ai_family = AF_INET6;
400 gai_error = getaddrinfo(host, NULL, &hints, &res);
401 if (gai_error) {
402 fprintf(stderr, "ndp: %s: %s\n", host,
403 gai_strerror(gai_error));
404 return 1;
405 }
406 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
407 sin->sin6_scope_id =
408 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
409 ea = (u_char *)LLADDR(&sdl_m);
410 if (ndp_ether_aton(eaddr, ea) == 0)
411 sdl_m.sdl_alen = 6;
412 flags = expire_time = 0;
413 while (argc-- > 0) {
414 if (strncmp(argv[0], "temp", 4) == 0) {
415 struct timeval time;
416
417 gettimeofday(&time, 0);
418 expire_time = time.tv_sec + 20 * 60;
419 } else if (strncmp(argv[0], "proxy", 5) == 0)
420 flags |= RTF_ANNOUNCE;
421 argv++;
422 }
423 if (rtmsg(RTM_GET) < 0) {
424 errx(1, "RTM_GET(%s) failed", host);
425 /* NOTREACHED */
426 }
427 sin = (struct sockaddr_in6 *)(rtm + 1);
428 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
429 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
430 if (sdl->sdl_family == AF_LINK &&
431 !(rtm->rtm_flags & RTF_GATEWAY)) {
432 switch (sdl->sdl_type) {
433 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
434 case IFT_ISO88024: case IFT_ISO88025:
435 case IFT_L2VLAN: case IFT_BRIDGE:
436 goto overwrite;
437 }
438 }
2/* $KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32/*
33 * Copyright (c) 1984, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * Sun Microsystems, Inc.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64/*
65 * Based on:
66 * "@(#) Copyright (c) 1984, 1993\n\
67 * The Regents of the University of California. All rights reserved.\n";
68 *
69 * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
70 */
71
72/*
73 * ndp - display, set, delete and flush neighbor cache
74 */
75
76
77#include <sys/param.h>
78#include <sys/file.h>
79#include <sys/ioctl.h>
80#include <sys/socket.h>
81#include <sys/sysctl.h>
82#include <sys/time.h>
83#include <sys/queue.h>
84
85#include <net/if.h>
86#include <net/if_var.h>
87#include <net/if_dl.h>
88#include <net/if_types.h>
89#include <net/route.h>
90
91#include <netinet/in.h>
92#include <netinet/if_ether.h>
93
94#include <netinet/icmp6.h>
95#include <netinet6/in6_var.h>
96#include <netinet6/nd6.h>
97
98#include <arpa/inet.h>
99
100#include <netdb.h>
101#include <errno.h>
102#include <nlist.h>
103#include <stdio.h>
104#include <string.h>
105#include <paths.h>
106#include <err.h>
107#include <stdlib.h>
108#include <fcntl.h>
109#include <unistd.h>
110#include "gmt2local.h"
111
112/* packing rule for routing socket */
113#define ROUNDUP(a) \
114 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
115#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
116
117#define NEXTADDR(w, s) \
118 if (rtm->rtm_addrs & (w)) { \
119 bcopy((char *)&s, cp, sizeof(s)); cp += SA_SIZE(&s);}
120
121
122static pid_t pid;
123static int nflag;
124static int tflag;
125static int32_t thiszone; /* time difference with gmt */
126static int s = -1;
127static int repeat = 0;
128
129char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */
130char host_buf[NI_MAXHOST]; /* getnameinfo() */
131char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
132
133int main(int, char **);
134int file(char *);
135void getsocket(void);
136int set(int, char **);
137void get(char *);
138int delete(char *);
139void dump(struct in6_addr *, int);
140static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
141static char *ether_str(struct sockaddr_dl *);
142int ndp_ether_aton(char *, u_char *);
143void usage(void);
144int rtmsg(int);
145void ifinfo(char *, int, char **);
146void rtrlist(void);
147void plist(void);
148void pfx_flush(void);
149void rtr_flush(void);
150void harmonize_rtr(void);
151#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
152static void getdefif(void);
153static void setdefif(char *);
154#endif
155static char *sec2str(time_t);
156static void ts_print(const struct timeval *);
157
158#ifdef ICMPV6CTL_ND6_DRLIST
159static char *rtpref_str[] = {
160 "medium", /* 00 */
161 "high", /* 01 */
162 "rsv", /* 10 */
163 "low" /* 11 */
164};
165#endif
166
167int mode = 0;
168char *arg = NULL;
169
170int
171main(argc, argv)
172 int argc;
173 char **argv;
174{
175 int ch;
176
177 pid = getpid();
178 thiszone = gmt2local(0);
179 while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
180 switch (ch) {
181 case 'a':
182 case 'c':
183 case 'p':
184 case 'r':
185 case 'H':
186 case 'P':
187 case 'R':
188 case 's':
189 case 'I':
190 if (mode) {
191 usage();
192 /*NOTREACHED*/
193 }
194 mode = ch;
195 arg = NULL;
196 break;
197 case 'd':
198 case 'f':
199 case 'i' :
200 if (mode) {
201 usage();
202 /*NOTREACHED*/
203 }
204 mode = ch;
205 arg = optarg;
206 break;
207 case 'n':
208 nflag = 1;
209 break;
210 case 't':
211 tflag = 1;
212 break;
213 case 'A':
214 if (mode) {
215 usage();
216 /*NOTREACHED*/
217 }
218 mode = 'a';
219 repeat = atoi(optarg);
220 if (repeat < 0) {
221 usage();
222 /*NOTREACHED*/
223 }
224 break;
225 default:
226 usage();
227 }
228
229 argc -= optind;
230 argv += optind;
231
232 switch (mode) {
233 case 'a':
234 case 'c':
235 if (argc != 0) {
236 usage();
237 /*NOTREACHED*/
238 }
239 dump(0, mode == 'c');
240 break;
241 case 'd':
242 if (argc != 0) {
243 usage();
244 /*NOTREACHED*/
245 }
246 delete(arg);
247 break;
248 case 'I':
249#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
250 if (argc > 1) {
251 usage();
252 /*NOTREACHED*/
253 } else if (argc == 1) {
254 if (strcmp(*argv, "delete") == 0 ||
255 if_nametoindex(*argv))
256 setdefif(*argv);
257 else
258 errx(1, "invalid interface %s", *argv);
259 }
260 getdefif(); /* always call it to print the result */
261 break;
262#else
263 errx(1, "not supported yet");
264 /*NOTREACHED*/
265#endif
266 case 'p':
267 if (argc != 0) {
268 usage();
269 /*NOTREACHED*/
270 }
271 plist();
272 break;
273 case 'i':
274 ifinfo(arg, argc, argv);
275 break;
276 case 'r':
277 if (argc != 0) {
278 usage();
279 /*NOTREACHED*/
280 }
281 rtrlist();
282 break;
283 case 's':
284 if (argc < 2 || argc > 4)
285 usage();
286 exit(set(argc, argv) ? 1 : 0);
287 case 'H':
288 if (argc != 0) {
289 usage();
290 /*NOTREACHED*/
291 }
292 harmonize_rtr();
293 break;
294 case 'P':
295 if (argc != 0) {
296 usage();
297 /*NOTREACHED*/
298 }
299 pfx_flush();
300 break;
301 case 'R':
302 if (argc != 0) {
303 usage();
304 /*NOTREACHED*/
305 }
306 rtr_flush();
307 break;
308 case 0:
309 if (argc != 1) {
310 usage();
311 /*NOTREACHED*/
312 }
313 get(argv[0]);
314 break;
315 }
316 exit(0);
317}
318
319/*
320 * Process a file to set standard ndp entries
321 */
322int
323file(name)
324 char *name;
325{
326 FILE *fp;
327 int i, retval;
328 char line[100], arg[5][50], *args[5];
329
330 if ((fp = fopen(name, "r")) == NULL) {
331 fprintf(stderr, "ndp: cannot open %s\n", name);
332 exit(1);
333 }
334 args[0] = &arg[0][0];
335 args[1] = &arg[1][0];
336 args[2] = &arg[2][0];
337 args[3] = &arg[3][0];
338 args[4] = &arg[4][0];
339 retval = 0;
340 while (fgets(line, sizeof(line), fp) != NULL) {
341 i = sscanf(line, "%49s %49s %49s %49s %49s",
342 arg[0], arg[1], arg[2], arg[3], arg[4]);
343 if (i < 2) {
344 fprintf(stderr, "ndp: bad line: %s\n", line);
345 retval = 1;
346 continue;
347 }
348 if (set(i, args))
349 retval = 1;
350 }
351 fclose(fp);
352 return (retval);
353}
354
355void
356getsocket()
357{
358 if (s < 0) {
359 s = socket(PF_ROUTE, SOCK_RAW, 0);
360 if (s < 0) {
361 err(1, "socket");
362 /* NOTREACHED */
363 }
364 }
365}
366
367struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
368struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
369struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
370int expire_time, flags, found_entry;
371struct {
372 struct rt_msghdr m_rtm;
373 char m_space[512];
374} m_rtmsg;
375
376/*
377 * Set an individual neighbor cache entry
378 */
379int
380set(argc, argv)
381 int argc;
382 char **argv;
383{
384 register struct sockaddr_in6 *sin = &sin_m;
385 register struct sockaddr_dl *sdl;
386 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
387 struct addrinfo hints, *res;
388 int gai_error;
389 u_char *ea;
390 char *host = argv[0], *eaddr = argv[1];
391
392 getsocket();
393 argc -= 2;
394 argv += 2;
395 sdl_m = blank_sdl;
396 sin_m = blank_sin;
397
398 bzero(&hints, sizeof(hints));
399 hints.ai_family = AF_INET6;
400 gai_error = getaddrinfo(host, NULL, &hints, &res);
401 if (gai_error) {
402 fprintf(stderr, "ndp: %s: %s\n", host,
403 gai_strerror(gai_error));
404 return 1;
405 }
406 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
407 sin->sin6_scope_id =
408 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
409 ea = (u_char *)LLADDR(&sdl_m);
410 if (ndp_ether_aton(eaddr, ea) == 0)
411 sdl_m.sdl_alen = 6;
412 flags = expire_time = 0;
413 while (argc-- > 0) {
414 if (strncmp(argv[0], "temp", 4) == 0) {
415 struct timeval time;
416
417 gettimeofday(&time, 0);
418 expire_time = time.tv_sec + 20 * 60;
419 } else if (strncmp(argv[0], "proxy", 5) == 0)
420 flags |= RTF_ANNOUNCE;
421 argv++;
422 }
423 if (rtmsg(RTM_GET) < 0) {
424 errx(1, "RTM_GET(%s) failed", host);
425 /* NOTREACHED */
426 }
427 sin = (struct sockaddr_in6 *)(rtm + 1);
428 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
429 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
430 if (sdl->sdl_family == AF_LINK &&
431 !(rtm->rtm_flags & RTF_GATEWAY)) {
432 switch (sdl->sdl_type) {
433 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
434 case IFT_ISO88024: case IFT_ISO88025:
435 case IFT_L2VLAN: case IFT_BRIDGE:
436 goto overwrite;
437 }
438 }
439 /*
440 * IPv4 arp command retries with sin_other = SIN_PROXY here.
441 */
442 fprintf(stderr, "set: cannot configure a new entry\n");
443 return 1;
444 }
445
446overwrite:
447 if (sdl->sdl_family != AF_LINK) {
448 printf("cannot intuit interface index and type for %s\n", host);
449 return (1);
450 }
451 sdl_m.sdl_type = sdl->sdl_type;
452 sdl_m.sdl_index = sdl->sdl_index;
453 return (rtmsg(RTM_ADD));
454}
455
456/*
457 * Display an individual neighbor cache entry
458 */
459void
460get(host)
461 char *host;
462{
463 struct sockaddr_in6 *sin = &sin_m;
464 struct addrinfo hints, *res;
465 int gai_error;
466
467 sin_m = blank_sin;
468 bzero(&hints, sizeof(hints));
469 hints.ai_family = AF_INET6;
470 gai_error = getaddrinfo(host, NULL, &hints, &res);
471 if (gai_error) {
472 fprintf(stderr, "ndp: %s: %s\n", host,
473 gai_strerror(gai_error));
474 return;
475 }
476 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
477 dump(&sin->sin6_addr, 0);
478 if (found_entry == 0) {
479 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
480 sizeof(host_buf), NULL ,0,
481 (nflag ? NI_NUMERICHOST : 0));
482 printf("%s (%s) -- no entry\n", host, host_buf);
483 exit(1);
484 }
485}
486
487/*
488 * Delete a neighbor cache entry
489 */
490int
491delete(host)
492 char *host;
493{
494 struct sockaddr_in6 *sin = &sin_m;
495 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
496 register char *cp = m_rtmsg.m_space;
497 struct sockaddr_dl *sdl;
498 struct addrinfo hints, *res;
499 int gai_error;
500
501 getsocket();
502 sin_m = blank_sin;
503
504 bzero(&hints, sizeof(hints));
505 hints.ai_family = AF_INET6;
506 gai_error = getaddrinfo(host, NULL, &hints, &res);
507 if (gai_error) {
508 fprintf(stderr, "ndp: %s: %s\n", host,
509 gai_strerror(gai_error));
510 return 1;
511 }
512 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
513 sin->sin6_scope_id =
514 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
515 if (rtmsg(RTM_GET) < 0) {
516 errx(1, "RTM_GET(%s) failed", host);
517 /* NOTREACHED */
518 }
519 sin = (struct sockaddr_in6 *)(rtm + 1);
520 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
521 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
522 if (sdl->sdl_family == AF_LINK &&
523 !(rtm->rtm_flags & RTF_GATEWAY)) {
524 goto delete;
525 }
439 fprintf(stderr, "set: cannot configure a new entry\n");
440 return 1;
441 }
442
443overwrite:
444 if (sdl->sdl_family != AF_LINK) {
445 printf("cannot intuit interface index and type for %s\n", host);
446 return (1);
447 }
448 sdl_m.sdl_type = sdl->sdl_type;
449 sdl_m.sdl_index = sdl->sdl_index;
450 return (rtmsg(RTM_ADD));
451}
452
453/*
454 * Display an individual neighbor cache entry
455 */
456void
457get(host)
458 char *host;
459{
460 struct sockaddr_in6 *sin = &sin_m;
461 struct addrinfo hints, *res;
462 int gai_error;
463
464 sin_m = blank_sin;
465 bzero(&hints, sizeof(hints));
466 hints.ai_family = AF_INET6;
467 gai_error = getaddrinfo(host, NULL, &hints, &res);
468 if (gai_error) {
469 fprintf(stderr, "ndp: %s: %s\n", host,
470 gai_strerror(gai_error));
471 return;
472 }
473 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
474 dump(&sin->sin6_addr, 0);
475 if (found_entry == 0) {
476 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
477 sizeof(host_buf), NULL ,0,
478 (nflag ? NI_NUMERICHOST : 0));
479 printf("%s (%s) -- no entry\n", host, host_buf);
480 exit(1);
481 }
482}
483
484/*
485 * Delete a neighbor cache entry
486 */
487int
488delete(host)
489 char *host;
490{
491 struct sockaddr_in6 *sin = &sin_m;
492 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
493 register char *cp = m_rtmsg.m_space;
494 struct sockaddr_dl *sdl;
495 struct addrinfo hints, *res;
496 int gai_error;
497
498 getsocket();
499 sin_m = blank_sin;
500
501 bzero(&hints, sizeof(hints));
502 hints.ai_family = AF_INET6;
503 gai_error = getaddrinfo(host, NULL, &hints, &res);
504 if (gai_error) {
505 fprintf(stderr, "ndp: %s: %s\n", host,
506 gai_strerror(gai_error));
507 return 1;
508 }
509 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
510 sin->sin6_scope_id =
511 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
512 if (rtmsg(RTM_GET) < 0) {
513 errx(1, "RTM_GET(%s) failed", host);
514 /* NOTREACHED */
515 }
516 sin = (struct sockaddr_in6 *)(rtm + 1);
517 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
518 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
519 if (sdl->sdl_family == AF_LINK &&
520 !(rtm->rtm_flags & RTF_GATEWAY)) {
521 goto delete;
522 }
526 /*
527 * IPv4 arp command retries with sin_other = SIN_PROXY here.
528 */
529 fprintf(stderr, "delete: cannot delete non-NDP entry\n");
530 return 1;
531 }
532
533delete:
534 if (sdl->sdl_family != AF_LINK) {
535 printf("cannot locate %s\n", host);
536 return (1);
537 }
538 /*
539 * need to reinit the field because it has rt_key
540 * but we want the actual address
541 */
542 NEXTADDR(RTA_DST, sin_m);
543 rtm->rtm_flags |= RTF_LLDATA;
544 if (rtmsg(RTM_DELETE) == 0) {
545 getnameinfo((struct sockaddr *)sin,
546 sin->sin6_len, host_buf,
547 sizeof(host_buf), NULL, 0,
548 (nflag ? NI_NUMERICHOST : 0));
549 printf("%s (%s) deleted\n", host, host_buf);
550 }
551
552 return 0;
553}
554
555#define W_ADDR 36
556#define W_LL 17
557#define W_IF 6
558
559/*
560 * Dump the entire neighbor cache
561 */
562void
563dump(addr, cflag)
564 struct in6_addr *addr;
565 int cflag;
566{
567 int mib[6];
568 size_t needed;
569 char *lim, *buf, *next;
570 struct rt_msghdr *rtm;
571 struct sockaddr_in6 *sin;
572 struct sockaddr_dl *sdl;
573 extern int h_errno;
574 struct in6_nbrinfo *nbi;
575 struct timeval time;
576 int addrwidth;
577 int llwidth;
578 int ifwidth;
579 char flgbuf[8];
580 char *ifname;
581
582 /* Print header */
583 if (!tflag && !cflag)
584 printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
585 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
586 W_IF, W_IF, "Netif", "Expire", "S", "Flags");
587
588again:;
589 mib[0] = CTL_NET;
590 mib[1] = PF_ROUTE;
591 mib[2] = 0;
592 mib[3] = AF_INET6;
593 mib[4] = NET_RT_FLAGS;
594#ifdef RTF_LLINFO
595 mib[5] = RTF_LLINFO;
596#else
597 mib[5] = 0;
598#endif
599 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
600 err(1, "sysctl(PF_ROUTE estimate)");
601 if (needed > 0) {
602 if ((buf = malloc(needed)) == NULL)
603 err(1, "malloc");
604 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
605 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
606 lim = buf + needed;
607 } else
608 buf = lim = NULL;
609
610 for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
611 int isrouter = 0, prbs = 0;
612
613 rtm = (struct rt_msghdr *)next;
614 sin = (struct sockaddr_in6 *)(rtm + 1);
615 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
616
617 /*
618 * Some OSes can produce a route that has the LINK flag but
619 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
620 * and BSD/OS, where xx is not the interface identifier on
621 * lo0). Such routes entry would annoy getnbrinfo() below,
622 * so we skip them.
623 * XXX: such routes should have the GATEWAY flag, not the
624 * LINK flag. However, there is rotten routing software
625 * that advertises all routes that have the GATEWAY flag.
626 * Thus, KAME kernel intentionally does not set the LINK flag.
627 * What is to be fixed is not ndp, but such routing software
628 * (and the kernel workaround)...
629 */
630 if (sdl->sdl_family != AF_LINK)
631 continue;
632
633 if (!(rtm->rtm_flags & RTF_HOST))
634 continue;
635
636 if (addr) {
637 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
638 continue;
639 found_entry = 1;
640 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
641 continue;
642 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
643 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
644 /* XXX: should scope id be filled in the kernel? */
645 if (sin->sin6_scope_id == 0)
646 sin->sin6_scope_id = sdl->sdl_index;
647 }
648 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
649 sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
650 if (cflag) {
651#ifdef RTF_WASCLONED
652 if (rtm->rtm_flags & RTF_WASCLONED)
653 delete(host_buf);
654#elif defined(RTF_CLONED)
655 if (rtm->rtm_flags & RTF_CLONED)
656 delete(host_buf);
657#else
658 delete(host_buf);
659#endif
660 continue;
661 }
662 gettimeofday(&time, 0);
663 if (tflag)
664 ts_print(&time);
665
666 addrwidth = strlen(host_buf);
667 if (addrwidth < W_ADDR)
668 addrwidth = W_ADDR;
669 llwidth = strlen(ether_str(sdl));
670 if (W_ADDR + W_LL - addrwidth > llwidth)
671 llwidth = W_ADDR + W_LL - addrwidth;
672 ifname = if_indextoname(sdl->sdl_index, ifix_buf);
673 if (!ifname)
674 ifname = "?";
675 ifwidth = strlen(ifname);
676 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
677 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
678
679 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
680 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
681
682 /* Print neighbor discovery specific informations */
683 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
684 if (nbi) {
685 if (nbi->expire > time.tv_sec) {
686 printf(" %-9.9s",
687 sec2str(nbi->expire - time.tv_sec));
688 } else if (nbi->expire == 0)
689 printf(" %-9.9s", "permanent");
690 else
691 printf(" %-9.9s", "expired");
692
693 switch (nbi->state) {
694 case ND6_LLINFO_NOSTATE:
695 printf(" N");
696 break;
697#ifdef ND6_LLINFO_WAITDELETE
698 case ND6_LLINFO_WAITDELETE:
699 printf(" W");
700 break;
701#endif
702 case ND6_LLINFO_INCOMPLETE:
703 printf(" I");
704 break;
705 case ND6_LLINFO_REACHABLE:
706 printf(" R");
707 break;
708 case ND6_LLINFO_STALE:
709 printf(" S");
710 break;
711 case ND6_LLINFO_DELAY:
712 printf(" D");
713 break;
714 case ND6_LLINFO_PROBE:
715 printf(" P");
716 break;
717 default:
718 printf(" ?");
719 break;
720 }
721
722 isrouter = nbi->isrouter;
723 prbs = nbi->asked;
724 } else {
725 warnx("failed to get neighbor information");
726 printf(" ");
727 }
728
729 /*
730 * other flags. R: router, P: proxy, W: ??
731 */
732 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
733 snprintf(flgbuf, sizeof(flgbuf), "%s%s",
734 isrouter ? "R" : "",
735 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
736 } else {
737 sin = (struct sockaddr_in6 *)
738 (sdl->sdl_len + (char *)sdl);
739#if 0 /* W and P are mystery even for us */
740 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
741 isrouter ? "R" : "",
742 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
743 (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
744 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
745#else
746 snprintf(flgbuf, sizeof(flgbuf), "%s%s",
747 isrouter ? "R" : "",
748 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
749#endif
750 }
751 printf(" %s", flgbuf);
752
753 if (prbs)
754 printf(" %d", prbs);
755
756 printf("\n");
757 }
758 if (buf != NULL)
759 free(buf);
760
761 if (repeat) {
762 printf("\n");
763 fflush(stdout);
764 sleep(repeat);
765 goto again;
766 }
767}
768
769static struct in6_nbrinfo *
770getnbrinfo(addr, ifindex, warning)
771 struct in6_addr *addr;
772 int ifindex;
773 int warning;
774{
775 static struct in6_nbrinfo nbi;
776 int s;
777
778 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
779 err(1, "socket");
780
781 bzero(&nbi, sizeof(nbi));
782 if_indextoname(ifindex, nbi.ifname);
783 nbi.addr = *addr;
784 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
785 if (warning)
786 warn("ioctl(SIOCGNBRINFO_IN6)");
787 close(s);
788 return(NULL);
789 }
790
791 close(s);
792 return(&nbi);
793}
794
795static char *
796ether_str(struct sockaddr_dl *sdl)
797{
798 static char hbuf[NI_MAXHOST];
799 char *cp;
800
801 if (sdl->sdl_alen == ETHER_ADDR_LEN) {
802 strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)),
803 sizeof(hbuf));
804 } else if (sdl->sdl_alen) {
805 int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
806 snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n);
807 } else
808 snprintf(hbuf, sizeof(hbuf), "(incomplete)");
809
810 return(hbuf);
811}
812
813int
814ndp_ether_aton(a, n)
815 char *a;
816 u_char *n;
817{
818 int i, o[6];
819
820 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
821 &o[3], &o[4], &o[5]);
822 if (i != 6) {
823 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
824 return (1);
825 }
826 for (i = 0; i < 6; i++)
827 n[i] = o[i];
828 return (0);
829}
830
831void
832usage()
833{
834 printf("usage: ndp [-nt] hostname\n");
835 printf(" ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
836 printf(" ndp [-nt] -A wait\n");
837 printf(" ndp [-nt] -d hostname\n");
838 printf(" ndp [-nt] -f filename\n");
839 printf(" ndp [-nt] -i interface [flags...]\n");
840#ifdef SIOCSDEFIFACE_IN6
841 printf(" ndp [-nt] -I [interface|delete]\n");
842#endif
843 printf(" ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
844 exit(1);
845}
846
847int
848rtmsg(cmd)
849 int cmd;
850{
851 static int seq;
852 int rlen;
853 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
854 register char *cp = m_rtmsg.m_space;
855 register int l;
856
857 errno = 0;
858 if (cmd == RTM_DELETE)
859 goto doit;
860 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
861 rtm->rtm_flags = flags;
862 rtm->rtm_version = RTM_VERSION;
863
864 switch (cmd) {
865 default:
866 fprintf(stderr, "ndp: internal wrong cmd\n");
867 exit(1);
868 case RTM_ADD:
869 rtm->rtm_addrs |= RTA_GATEWAY;
870 if (expire_time) {
871 rtm->rtm_rmx.rmx_expire = expire_time;
872 rtm->rtm_inits = RTV_EXPIRE;
873 }
874 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
875#if 0 /* we don't support ipv6addr/128 type proxying */
876 if (rtm->rtm_flags & RTF_ANNOUNCE) {
877 rtm->rtm_flags &= ~RTF_HOST;
878 rtm->rtm_addrs |= RTA_NETMASK;
879 }
880#endif
881 /* FALLTHROUGH */
882 case RTM_GET:
883 rtm->rtm_addrs |= RTA_DST;
884 }
885
886 NEXTADDR(RTA_DST, sin_m);
887 NEXTADDR(RTA_GATEWAY, sdl_m);
888#if 0 /* we don't support ipv6addr/128 type proxying */
889 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
890 NEXTADDR(RTA_NETMASK, so_mask);
891#endif
892
893 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
894doit:
895 l = rtm->rtm_msglen;
896 rtm->rtm_seq = ++seq;
897 rtm->rtm_type = cmd;
898 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
899 if (errno != ESRCH || cmd != RTM_DELETE) {
900 err(1, "writing to routing socket");
901 /* NOTREACHED */
902 }
903 }
904 do {
905 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
906 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
907 if (l < 0)
908 (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
909 strerror(errno));
910 return (0);
911}
912
913void
914ifinfo(ifname, argc, argv)
915 char *ifname;
916 int argc;
917 char **argv;
918{
919 struct in6_ndireq nd;
920 int i, s;
921 u_int32_t newflags;
922#ifdef IPV6CTL_USETEMPADDR
923 u_int8_t nullbuf[8];
924#endif
925
926 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
927 err(1, "socket");
928 /* NOTREACHED */
929 }
930 bzero(&nd, sizeof(nd));
931 strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
932 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
933 err(1, "ioctl(SIOCGIFINFO_IN6)");
934 /* NOTREACHED */
935 }
936#define ND nd.ndi
937 newflags = ND.flags;
938 for (i = 0; i < argc; i++) {
939 int clear = 0;
940 char *cp = argv[i];
941
942 if (*cp == '-') {
943 clear = 1;
944 cp++;
945 }
946
947#define SETFLAG(s, f) \
948 do {\
949 if (strcmp(cp, (s)) == 0) {\
950 if (clear)\
951 newflags &= ~(f);\
952 else\
953 newflags |= (f);\
954 }\
955 } while (0)
956/*
957 * XXX: this macro is not 100% correct, in that it matches "nud" against
958 * "nudbogus". But we just let it go since this is minor.
959 */
960#define SETVALUE(f, v) \
961 do { \
962 char *valptr; \
963 unsigned long newval; \
964 v = 0; /* unspecified */ \
965 if (strncmp(cp, f, strlen(f)) == 0) { \
966 valptr = strchr(cp, '='); \
967 if (valptr == NULL) \
968 err(1, "syntax error in %s field", (f)); \
969 errno = 0; \
970 newval = strtoul(++valptr, NULL, 0); \
971 if (errno) \
972 err(1, "syntax error in %s's value", (f)); \
973 v = newval; \
974 } \
975 } while (0)
976
977 SETFLAG("disabled", ND6_IFF_IFDISABLED);
978 SETFLAG("nud", ND6_IFF_PERFORMNUD);
979#ifdef ND6_IFF_ACCEPT_RTADV
980 SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
981#endif
982#ifdef ND6_IFF_AUTO_LINKLOCAL
983 SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
984#endif
985#ifdef ND6_IFF_NO_PREFER_IFACE
986 SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE);
987#endif
988 SETVALUE("basereachable", ND.basereachable);
989 SETVALUE("retrans", ND.retrans);
990 SETVALUE("curhlim", ND.chlim);
991
992 ND.flags = newflags;
993 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
994 err(1, "ioctl(SIOCSIFINFO_IN6)");
995 /* NOTREACHED */
996 }
997#undef SETFLAG
998#undef SETVALUE
999 }
1000
1001 if (!ND.initialized) {
1002 errx(1, "%s: not initialized yet", ifname);
1003 /* NOTREACHED */
1004 }
1005
1006 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1007 err(1, "ioctl(SIOCGIFINFO_IN6)");
1008 /* NOTREACHED */
1009 }
1010 printf("linkmtu=%d", ND.linkmtu);
1011 printf(", maxmtu=%d", ND.maxmtu);
1012 printf(", curhlim=%d", ND.chlim);
1013 printf(", basereachable=%ds%dms",
1014 ND.basereachable / 1000, ND.basereachable % 1000);
1015 printf(", reachable=%ds", ND.reachable);
1016 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
1017#ifdef IPV6CTL_USETEMPADDR
1018 memset(nullbuf, 0, sizeof(nullbuf));
1019 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
1020 int j;
1021 u_int8_t *rbuf;
1022
1023 for (i = 0; i < 3; i++) {
1024 switch (i) {
1025 case 0:
1026 printf("\nRandom seed(0): ");
1027 rbuf = ND.randomseed0;
1028 break;
1029 case 1:
1030 printf("\nRandom seed(1): ");
1031 rbuf = ND.randomseed1;
1032 break;
1033 case 2:
1034 printf("\nRandom ID: ");
1035 rbuf = ND.randomid;
1036 break;
1037 default:
1038 errx(1, "impossible case for tempaddr display");
1039 }
1040 for (j = 0; j < 8; j++)
1041 printf("%02x", rbuf[j]);
1042 }
1043 }
1044#endif
1045 if (ND.flags) {
1046 printf("\nFlags: ");
1047#ifdef ND6_IFF_IFDISABLED
1048 if ((ND.flags & ND6_IFF_IFDISABLED))
1049 printf("disabled ");
1050#endif
1051 if ((ND.flags & ND6_IFF_PERFORMNUD))
1052 printf("nud ");
1053#ifdef ND6_IFF_ACCEPT_RTADV
1054 if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1055 printf("accept_rtadv ");
1056#endif
1057#ifdef ND6_IFF_AUTO_LINKLOCAL
1058 if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
1059 printf("auto_linklocal ");
1060#endif
1061#ifdef ND6_IFF_NO_PREFER_IFACE
1062 if ((ND.flags & ND6_IFF_NO_PREFER_IFACE))
1063 printf("no_prefer_iface ");
1064#endif
1065 }
1066 putc('\n', stdout);
1067#undef ND
1068
1069 close(s);
1070}
1071
1072#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
1073#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
1074#endif
1075
1076void
1077rtrlist()
1078{
1079#ifdef ICMPV6CTL_ND6_DRLIST
1080 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
1081 char *buf;
1082 struct in6_defrouter *p, *ep;
1083 size_t l;
1084 struct timeval time;
1085
1086 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1087 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1088 /*NOTREACHED*/
1089 }
1090 if (l == 0)
1091 return;
1092 buf = malloc(l);
1093 if (!buf) {
1094 err(1, "malloc");
1095 /*NOTREACHED*/
1096 }
1097 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1098 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1099 /*NOTREACHED*/
1100 }
1101
1102 ep = (struct in6_defrouter *)(buf + l);
1103 for (p = (struct in6_defrouter *)buf; p < ep; p++) {
1104 int rtpref;
1105
1106 if (getnameinfo((struct sockaddr *)&p->rtaddr,
1107 p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1108 (nflag ? NI_NUMERICHOST : 0)) != 0)
1109 strlcpy(host_buf, "?", sizeof(host_buf));
1110
1111 printf("%s if=%s", host_buf,
1112 if_indextoname(p->if_index, ifix_buf));
1113 printf(", flags=%s%s",
1114 p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1115 p->flags & ND_RA_FLAG_OTHER ? "O" : "");
1116 rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
1117 printf(", pref=%s", rtpref_str[rtpref]);
1118
1119 gettimeofday(&time, 0);
1120 if (p->expire == 0)
1121 printf(", expire=Never\n");
1122 else
1123 printf(", expire=%s\n",
1124 sec2str(p->expire - time.tv_sec));
1125 }
1126 free(buf);
1127#else
1128 struct in6_drlist dr;
1129 int s, i;
1130 struct timeval time;
1131
1132 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1133 err(1, "socket");
1134 /* NOTREACHED */
1135 }
1136 bzero(&dr, sizeof(dr));
1137 strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
1138 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1139 err(1, "ioctl(SIOCGDRLST_IN6)");
1140 /* NOTREACHED */
1141 }
1142#define DR dr.defrouter[i]
1143 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
1144 struct sockaddr_in6 sin6;
1145
1146 bzero(&sin6, sizeof(sin6));
1147 sin6.sin6_family = AF_INET6;
1148 sin6.sin6_len = sizeof(sin6);
1149 sin6.sin6_addr = DR.rtaddr;
1150 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1151 sizeof(host_buf), NULL, 0,
1152 (nflag ? NI_NUMERICHOST : 0));
1153
1154 printf("%s if=%s", host_buf,
1155 if_indextoname(DR.if_index, ifix_buf));
1156 printf(", flags=%s%s",
1157 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1158 DR.flags & ND_RA_FLAG_OTHER ? "O" : "");
1159 gettimeofday(&time, 0);
1160 if (DR.expire == 0)
1161 printf(", expire=Never\n");
1162 else
1163 printf(", expire=%s\n",
1164 sec2str(DR.expire - time.tv_sec));
1165 }
1166#undef DR
1167 close(s);
1168#endif
1169}
1170
1171void
1172plist()
1173{
1174#ifdef ICMPV6CTL_ND6_PRLIST
1175 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
1176 char *buf;
1177 struct in6_prefix *p, *ep, *n;
1178 struct sockaddr_in6 *advrtr;
1179 size_t l;
1180 struct timeval time;
1181 const int niflags = NI_NUMERICHOST;
1182 int ninflags = nflag ? NI_NUMERICHOST : 0;
1183 char namebuf[NI_MAXHOST];
1184
1185 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1186 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1187 /*NOTREACHED*/
1188 }
1189 buf = malloc(l);
1190 if (!buf) {
1191 err(1, "malloc");
1192 /*NOTREACHED*/
1193 }
1194 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1195 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1196 /*NOTREACHED*/
1197 }
1198
1199 ep = (struct in6_prefix *)(buf + l);
1200 for (p = (struct in6_prefix *)buf; p < ep; p = n) {
1201 advrtr = (struct sockaddr_in6 *)(p + 1);
1202 n = (struct in6_prefix *)&advrtr[p->advrtrs];
1203
1204 if (getnameinfo((struct sockaddr *)&p->prefix,
1205 p->prefix.sin6_len, namebuf, sizeof(namebuf),
1206 NULL, 0, niflags) != 0)
1207 strlcpy(namebuf, "?", sizeof(namebuf));
1208 printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1209 if_indextoname(p->if_index, ifix_buf));
1210
1211 gettimeofday(&time, 0);
1212 /*
1213 * meaning of fields, especially flags, is very different
1214 * by origin. notify the difference to the users.
1215 */
1216 printf("flags=%s%s%s%s%s",
1217 p->raflags.onlink ? "L" : "",
1218 p->raflags.autonomous ? "A" : "",
1219 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1220 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
1221#ifdef NDPRF_HOME
1222 (p->flags & NDPRF_HOME) != 0 ? "H" : ""
1223#else
1224 ""
1225#endif
1226 );
1227 if (p->vltime == ND6_INFINITE_LIFETIME)
1228 printf(" vltime=infinity");
1229 else
1230 printf(" vltime=%lu", (unsigned long)p->vltime);
1231 if (p->pltime == ND6_INFINITE_LIFETIME)
1232 printf(", pltime=infinity");
1233 else
1234 printf(", pltime=%lu", (unsigned long)p->pltime);
1235 if (p->expire == 0)
1236 printf(", expire=Never");
1237 else if (p->expire >= time.tv_sec)
1238 printf(", expire=%s",
1239 sec2str(p->expire - time.tv_sec));
1240 else
1241 printf(", expired");
1242 printf(", ref=%d", p->refcnt);
1243 printf("\n");
1244 /*
1245 * "advertising router" list is meaningful only if the prefix
1246 * information is from RA.
1247 */
1248 if (p->advrtrs) {
1249 int j;
1250 struct sockaddr_in6 *sin6;
1251
1252 sin6 = advrtr;
1253 printf(" advertised by\n");
1254 for (j = 0; j < p->advrtrs; j++) {
1255 struct in6_nbrinfo *nbi;
1256
1257 if (getnameinfo((struct sockaddr *)sin6,
1258 sin6->sin6_len, namebuf, sizeof(namebuf),
1259 NULL, 0, ninflags) != 0)
1260 strlcpy(namebuf, "?", sizeof(namebuf));
1261 printf(" %s", namebuf);
1262
1263 nbi = getnbrinfo(&sin6->sin6_addr,
1264 p->if_index, 0);
1265 if (nbi) {
1266 switch (nbi->state) {
1267 case ND6_LLINFO_REACHABLE:
1268 case ND6_LLINFO_STALE:
1269 case ND6_LLINFO_DELAY:
1270 case ND6_LLINFO_PROBE:
1271 printf(" (reachable)\n");
1272 break;
1273 default:
1274 printf(" (unreachable)\n");
1275 }
1276 } else
1277 printf(" (no neighbor state)\n");
1278 sin6++;
1279 }
1280 } else
1281 printf(" No advertising router\n");
1282 }
1283 free(buf);
1284#else
1285 struct in6_prlist pr;
1286 int s, i;
1287 struct timeval time;
1288
1289 gettimeofday(&time, 0);
1290
1291 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1292 err(1, "socket");
1293 /* NOTREACHED */
1294 }
1295 bzero(&pr, sizeof(pr));
1296 strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
1297 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1298 err(1, "ioctl(SIOCGPRLST_IN6)");
1299 /* NOTREACHED */
1300 }
1301#define PR pr.prefix[i]
1302 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
1303 struct sockaddr_in6 p6;
1304 char namebuf[NI_MAXHOST];
1305 int niflags;
1306
1307#ifdef NDPRF_ONLINK
1308 p6 = PR.prefix;
1309#else
1310 memset(&p6, 0, sizeof(p6));
1311 p6.sin6_family = AF_INET6;
1312 p6.sin6_len = sizeof(p6);
1313 p6.sin6_addr = PR.prefix;
1314#endif
1315 niflags = NI_NUMERICHOST;
1316 if (getnameinfo((struct sockaddr *)&p6,
1317 sizeof(p6), namebuf, sizeof(namebuf),
1318 NULL, 0, niflags)) {
1319 warnx("getnameinfo failed");
1320 continue;
1321 }
1322 printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1323 if_indextoname(PR.if_index, ifix_buf));
1324
1325 gettimeofday(&time, 0);
1326 /*
1327 * meaning of fields, especially flags, is very different
1328 * by origin. notify the difference to the users.
1329 */
1330#if 0
1331 printf(" %s",
1332 PR.origin == PR_ORIG_RA ? "" : "advertise: ");
1333#endif
1334#ifdef NDPRF_ONLINK
1335 printf("flags=%s%s%s%s%s",
1336 PR.raflags.onlink ? "L" : "",
1337 PR.raflags.autonomous ? "A" : "",
1338 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1339 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
1340#ifdef NDPRF_HOME
1341 (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
1342#else
1343 ""
1344#endif
1345 );
1346#else
1347 printf("flags=%s%s",
1348 PR.raflags.onlink ? "L" : "",
1349 PR.raflags.autonomous ? "A" : "");
1350#endif
1351 if (PR.vltime == ND6_INFINITE_LIFETIME)
1352 printf(" vltime=infinity");
1353 else
1354 printf(" vltime=%lu", PR.vltime);
1355 if (PR.pltime == ND6_INFINITE_LIFETIME)
1356 printf(", pltime=infinity");
1357 else
1358 printf(", pltime=%lu", PR.pltime);
1359 if (PR.expire == 0)
1360 printf(", expire=Never");
1361 else if (PR.expire >= time.tv_sec)
1362 printf(", expire=%s",
1363 sec2str(PR.expire - time.tv_sec));
1364 else
1365 printf(", expired");
1366#ifdef NDPRF_ONLINK
1367 printf(", ref=%d", PR.refcnt);
1368#endif
1369#if 0
1370 switch (PR.origin) {
1371 case PR_ORIG_RA:
1372 printf(", origin=RA");
1373 break;
1374 case PR_ORIG_RR:
1375 printf(", origin=RR");
1376 break;
1377 case PR_ORIG_STATIC:
1378 printf(", origin=static");
1379 break;
1380 case PR_ORIG_KERNEL:
1381 printf(", origin=kernel");
1382 break;
1383 default:
1384 printf(", origin=?");
1385 break;
1386 }
1387#endif
1388 printf("\n");
1389 /*
1390 * "advertising router" list is meaningful only if the prefix
1391 * information is from RA.
1392 */
1393 if (0 && /* prefix origin is almost obsolted */
1394 PR.origin != PR_ORIG_RA)
1395 ;
1396 else if (PR.advrtrs) {
1397 int j;
1398 printf(" advertised by\n");
1399 for (j = 0; j < PR.advrtrs; j++) {
1400 struct sockaddr_in6 sin6;
1401 struct in6_nbrinfo *nbi;
1402
1403 bzero(&sin6, sizeof(sin6));
1404 sin6.sin6_family = AF_INET6;
1405 sin6.sin6_len = sizeof(sin6);
1406 sin6.sin6_addr = PR.advrtr[j];
1407 sin6.sin6_scope_id = PR.if_index; /* XXX */
1408 getnameinfo((struct sockaddr *)&sin6,
1409 sin6.sin6_len, host_buf,
1410 sizeof(host_buf), NULL, 0,
1411 (nflag ? NI_NUMERICHOST : 0));
1412 printf(" %s", host_buf);
1413
1414 nbi = getnbrinfo(&sin6.sin6_addr,
1415 PR.if_index, 0);
1416 if (nbi) {
1417 switch (nbi->state) {
1418 case ND6_LLINFO_REACHABLE:
1419 case ND6_LLINFO_STALE:
1420 case ND6_LLINFO_DELAY:
1421 case ND6_LLINFO_PROBE:
1422 printf(" (reachable)\n");
1423 break;
1424 default:
1425 printf(" (unreachable)\n");
1426 }
1427 } else
1428 printf(" (no neighbor state)\n");
1429 }
1430 if (PR.advrtrs > DRLSTSIZ)
1431 printf(" and %d routers\n",
1432 PR.advrtrs - DRLSTSIZ);
1433 } else
1434 printf(" No advertising router\n");
1435 }
1436#undef PR
1437 close(s);
1438#endif
1439}
1440
1441void
1442pfx_flush()
1443{
1444 char dummyif[IFNAMSIZ+8];
1445 int s;
1446
1447 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1448 err(1, "socket");
1449 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1450 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1451 err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1452}
1453
1454void
1455rtr_flush()
1456{
1457 char dummyif[IFNAMSIZ+8];
1458 int s;
1459
1460 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1461 err(1, "socket");
1462 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1463 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1464 err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1465
1466 close(s);
1467}
1468
1469void
1470harmonize_rtr()
1471{
1472 char dummyif[IFNAMSIZ+8];
1473 int s;
1474
1475 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1476 err(1, "socket");
1477 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1478 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1479 err(1, "ioctl(SIOCSNDFLUSH_IN6)");
1480
1481 close(s);
1482}
1483
1484#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
1485static void
1486setdefif(ifname)
1487 char *ifname;
1488{
1489 struct in6_ndifreq ndifreq;
1490 unsigned int ifindex;
1491
1492 if (strcasecmp(ifname, "delete") == 0)
1493 ifindex = 0;
1494 else {
1495 if ((ifindex = if_nametoindex(ifname)) == 0)
1496 err(1, "failed to resolve i/f index for %s", ifname);
1497 }
1498
1499 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1500 err(1, "socket");
1501
1502 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1503 ndifreq.ifindex = ifindex;
1504
1505 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1506 err(1, "ioctl(SIOCSDEFIFACE_IN6)");
1507
1508 close(s);
1509}
1510
1511static void
1512getdefif()
1513{
1514 struct in6_ndifreq ndifreq;
1515 char ifname[IFNAMSIZ+8];
1516
1517 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1518 err(1, "socket");
1519
1520 memset(&ndifreq, 0, sizeof(ndifreq));
1521 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1522
1523 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1524 err(1, "ioctl(SIOCGDEFIFACE_IN6)");
1525
1526 if (ndifreq.ifindex == 0)
1527 printf("No default interface.\n");
1528 else {
1529 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1530 err(1, "failed to resolve ifname for index %lu",
1531 ndifreq.ifindex);
1532 printf("ND default interface = %s\n", ifname);
1533 }
1534
1535 close(s);
1536}
1537#endif
1538
1539static char *
1540sec2str(total)
1541 time_t total;
1542{
1543 static char result[256];
1544 int days, hours, mins, secs;
1545 int first = 1;
1546 char *p = result;
1547 char *ep = &result[sizeof(result)];
1548 int n;
1549
1550 days = total / 3600 / 24;
1551 hours = (total / 3600) % 24;
1552 mins = (total / 60) % 60;
1553 secs = total % 60;
1554
1555 if (days) {
1556 first = 0;
1557 n = snprintf(p, ep - p, "%dd", days);
1558 if (n < 0 || n >= ep - p)
1559 return "?";
1560 p += n;
1561 }
1562 if (!first || hours) {
1563 first = 0;
1564 n = snprintf(p, ep - p, "%dh", hours);
1565 if (n < 0 || n >= ep - p)
1566 return "?";
1567 p += n;
1568 }
1569 if (!first || mins) {
1570 first = 0;
1571 n = snprintf(p, ep - p, "%dm", mins);
1572 if (n < 0 || n >= ep - p)
1573 return "?";
1574 p += n;
1575 }
1576 snprintf(p, ep - p, "%ds", secs);
1577
1578 return(result);
1579}
1580
1581/*
1582 * Print the timestamp
1583 * from tcpdump/util.c
1584 */
1585static void
1586ts_print(tvp)
1587 const struct timeval *tvp;
1588{
1589 int s;
1590
1591 /* Default */
1592 s = (tvp->tv_sec + thiszone) % 86400;
1593 (void)printf("%02d:%02d:%02d.%06u ",
1594 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
1595}
1596
1597#undef NEXTADDR
523 fprintf(stderr, "delete: cannot delete non-NDP entry\n");
524 return 1;
525 }
526
527delete:
528 if (sdl->sdl_family != AF_LINK) {
529 printf("cannot locate %s\n", host);
530 return (1);
531 }
532 /*
533 * need to reinit the field because it has rt_key
534 * but we want the actual address
535 */
536 NEXTADDR(RTA_DST, sin_m);
537 rtm->rtm_flags |= RTF_LLDATA;
538 if (rtmsg(RTM_DELETE) == 0) {
539 getnameinfo((struct sockaddr *)sin,
540 sin->sin6_len, host_buf,
541 sizeof(host_buf), NULL, 0,
542 (nflag ? NI_NUMERICHOST : 0));
543 printf("%s (%s) deleted\n", host, host_buf);
544 }
545
546 return 0;
547}
548
549#define W_ADDR 36
550#define W_LL 17
551#define W_IF 6
552
553/*
554 * Dump the entire neighbor cache
555 */
556void
557dump(addr, cflag)
558 struct in6_addr *addr;
559 int cflag;
560{
561 int mib[6];
562 size_t needed;
563 char *lim, *buf, *next;
564 struct rt_msghdr *rtm;
565 struct sockaddr_in6 *sin;
566 struct sockaddr_dl *sdl;
567 extern int h_errno;
568 struct in6_nbrinfo *nbi;
569 struct timeval time;
570 int addrwidth;
571 int llwidth;
572 int ifwidth;
573 char flgbuf[8];
574 char *ifname;
575
576 /* Print header */
577 if (!tflag && !cflag)
578 printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
579 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
580 W_IF, W_IF, "Netif", "Expire", "S", "Flags");
581
582again:;
583 mib[0] = CTL_NET;
584 mib[1] = PF_ROUTE;
585 mib[2] = 0;
586 mib[3] = AF_INET6;
587 mib[4] = NET_RT_FLAGS;
588#ifdef RTF_LLINFO
589 mib[5] = RTF_LLINFO;
590#else
591 mib[5] = 0;
592#endif
593 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
594 err(1, "sysctl(PF_ROUTE estimate)");
595 if (needed > 0) {
596 if ((buf = malloc(needed)) == NULL)
597 err(1, "malloc");
598 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
599 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
600 lim = buf + needed;
601 } else
602 buf = lim = NULL;
603
604 for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
605 int isrouter = 0, prbs = 0;
606
607 rtm = (struct rt_msghdr *)next;
608 sin = (struct sockaddr_in6 *)(rtm + 1);
609 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
610
611 /*
612 * Some OSes can produce a route that has the LINK flag but
613 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
614 * and BSD/OS, where xx is not the interface identifier on
615 * lo0). Such routes entry would annoy getnbrinfo() below,
616 * so we skip them.
617 * XXX: such routes should have the GATEWAY flag, not the
618 * LINK flag. However, there is rotten routing software
619 * that advertises all routes that have the GATEWAY flag.
620 * Thus, KAME kernel intentionally does not set the LINK flag.
621 * What is to be fixed is not ndp, but such routing software
622 * (and the kernel workaround)...
623 */
624 if (sdl->sdl_family != AF_LINK)
625 continue;
626
627 if (!(rtm->rtm_flags & RTF_HOST))
628 continue;
629
630 if (addr) {
631 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
632 continue;
633 found_entry = 1;
634 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
635 continue;
636 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
637 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
638 /* XXX: should scope id be filled in the kernel? */
639 if (sin->sin6_scope_id == 0)
640 sin->sin6_scope_id = sdl->sdl_index;
641 }
642 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
643 sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
644 if (cflag) {
645#ifdef RTF_WASCLONED
646 if (rtm->rtm_flags & RTF_WASCLONED)
647 delete(host_buf);
648#elif defined(RTF_CLONED)
649 if (rtm->rtm_flags & RTF_CLONED)
650 delete(host_buf);
651#else
652 delete(host_buf);
653#endif
654 continue;
655 }
656 gettimeofday(&time, 0);
657 if (tflag)
658 ts_print(&time);
659
660 addrwidth = strlen(host_buf);
661 if (addrwidth < W_ADDR)
662 addrwidth = W_ADDR;
663 llwidth = strlen(ether_str(sdl));
664 if (W_ADDR + W_LL - addrwidth > llwidth)
665 llwidth = W_ADDR + W_LL - addrwidth;
666 ifname = if_indextoname(sdl->sdl_index, ifix_buf);
667 if (!ifname)
668 ifname = "?";
669 ifwidth = strlen(ifname);
670 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
671 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
672
673 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
674 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
675
676 /* Print neighbor discovery specific informations */
677 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
678 if (nbi) {
679 if (nbi->expire > time.tv_sec) {
680 printf(" %-9.9s",
681 sec2str(nbi->expire - time.tv_sec));
682 } else if (nbi->expire == 0)
683 printf(" %-9.9s", "permanent");
684 else
685 printf(" %-9.9s", "expired");
686
687 switch (nbi->state) {
688 case ND6_LLINFO_NOSTATE:
689 printf(" N");
690 break;
691#ifdef ND6_LLINFO_WAITDELETE
692 case ND6_LLINFO_WAITDELETE:
693 printf(" W");
694 break;
695#endif
696 case ND6_LLINFO_INCOMPLETE:
697 printf(" I");
698 break;
699 case ND6_LLINFO_REACHABLE:
700 printf(" R");
701 break;
702 case ND6_LLINFO_STALE:
703 printf(" S");
704 break;
705 case ND6_LLINFO_DELAY:
706 printf(" D");
707 break;
708 case ND6_LLINFO_PROBE:
709 printf(" P");
710 break;
711 default:
712 printf(" ?");
713 break;
714 }
715
716 isrouter = nbi->isrouter;
717 prbs = nbi->asked;
718 } else {
719 warnx("failed to get neighbor information");
720 printf(" ");
721 }
722
723 /*
724 * other flags. R: router, P: proxy, W: ??
725 */
726 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
727 snprintf(flgbuf, sizeof(flgbuf), "%s%s",
728 isrouter ? "R" : "",
729 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
730 } else {
731 sin = (struct sockaddr_in6 *)
732 (sdl->sdl_len + (char *)sdl);
733#if 0 /* W and P are mystery even for us */
734 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
735 isrouter ? "R" : "",
736 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
737 (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
738 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
739#else
740 snprintf(flgbuf, sizeof(flgbuf), "%s%s",
741 isrouter ? "R" : "",
742 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
743#endif
744 }
745 printf(" %s", flgbuf);
746
747 if (prbs)
748 printf(" %d", prbs);
749
750 printf("\n");
751 }
752 if (buf != NULL)
753 free(buf);
754
755 if (repeat) {
756 printf("\n");
757 fflush(stdout);
758 sleep(repeat);
759 goto again;
760 }
761}
762
763static struct in6_nbrinfo *
764getnbrinfo(addr, ifindex, warning)
765 struct in6_addr *addr;
766 int ifindex;
767 int warning;
768{
769 static struct in6_nbrinfo nbi;
770 int s;
771
772 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
773 err(1, "socket");
774
775 bzero(&nbi, sizeof(nbi));
776 if_indextoname(ifindex, nbi.ifname);
777 nbi.addr = *addr;
778 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
779 if (warning)
780 warn("ioctl(SIOCGNBRINFO_IN6)");
781 close(s);
782 return(NULL);
783 }
784
785 close(s);
786 return(&nbi);
787}
788
789static char *
790ether_str(struct sockaddr_dl *sdl)
791{
792 static char hbuf[NI_MAXHOST];
793 char *cp;
794
795 if (sdl->sdl_alen == ETHER_ADDR_LEN) {
796 strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)),
797 sizeof(hbuf));
798 } else if (sdl->sdl_alen) {
799 int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
800 snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n);
801 } else
802 snprintf(hbuf, sizeof(hbuf), "(incomplete)");
803
804 return(hbuf);
805}
806
807int
808ndp_ether_aton(a, n)
809 char *a;
810 u_char *n;
811{
812 int i, o[6];
813
814 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
815 &o[3], &o[4], &o[5]);
816 if (i != 6) {
817 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
818 return (1);
819 }
820 for (i = 0; i < 6; i++)
821 n[i] = o[i];
822 return (0);
823}
824
825void
826usage()
827{
828 printf("usage: ndp [-nt] hostname\n");
829 printf(" ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
830 printf(" ndp [-nt] -A wait\n");
831 printf(" ndp [-nt] -d hostname\n");
832 printf(" ndp [-nt] -f filename\n");
833 printf(" ndp [-nt] -i interface [flags...]\n");
834#ifdef SIOCSDEFIFACE_IN6
835 printf(" ndp [-nt] -I [interface|delete]\n");
836#endif
837 printf(" ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
838 exit(1);
839}
840
841int
842rtmsg(cmd)
843 int cmd;
844{
845 static int seq;
846 int rlen;
847 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
848 register char *cp = m_rtmsg.m_space;
849 register int l;
850
851 errno = 0;
852 if (cmd == RTM_DELETE)
853 goto doit;
854 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
855 rtm->rtm_flags = flags;
856 rtm->rtm_version = RTM_VERSION;
857
858 switch (cmd) {
859 default:
860 fprintf(stderr, "ndp: internal wrong cmd\n");
861 exit(1);
862 case RTM_ADD:
863 rtm->rtm_addrs |= RTA_GATEWAY;
864 if (expire_time) {
865 rtm->rtm_rmx.rmx_expire = expire_time;
866 rtm->rtm_inits = RTV_EXPIRE;
867 }
868 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
869#if 0 /* we don't support ipv6addr/128 type proxying */
870 if (rtm->rtm_flags & RTF_ANNOUNCE) {
871 rtm->rtm_flags &= ~RTF_HOST;
872 rtm->rtm_addrs |= RTA_NETMASK;
873 }
874#endif
875 /* FALLTHROUGH */
876 case RTM_GET:
877 rtm->rtm_addrs |= RTA_DST;
878 }
879
880 NEXTADDR(RTA_DST, sin_m);
881 NEXTADDR(RTA_GATEWAY, sdl_m);
882#if 0 /* we don't support ipv6addr/128 type proxying */
883 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
884 NEXTADDR(RTA_NETMASK, so_mask);
885#endif
886
887 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
888doit:
889 l = rtm->rtm_msglen;
890 rtm->rtm_seq = ++seq;
891 rtm->rtm_type = cmd;
892 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
893 if (errno != ESRCH || cmd != RTM_DELETE) {
894 err(1, "writing to routing socket");
895 /* NOTREACHED */
896 }
897 }
898 do {
899 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
900 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
901 if (l < 0)
902 (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
903 strerror(errno));
904 return (0);
905}
906
907void
908ifinfo(ifname, argc, argv)
909 char *ifname;
910 int argc;
911 char **argv;
912{
913 struct in6_ndireq nd;
914 int i, s;
915 u_int32_t newflags;
916#ifdef IPV6CTL_USETEMPADDR
917 u_int8_t nullbuf[8];
918#endif
919
920 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
921 err(1, "socket");
922 /* NOTREACHED */
923 }
924 bzero(&nd, sizeof(nd));
925 strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
926 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
927 err(1, "ioctl(SIOCGIFINFO_IN6)");
928 /* NOTREACHED */
929 }
930#define ND nd.ndi
931 newflags = ND.flags;
932 for (i = 0; i < argc; i++) {
933 int clear = 0;
934 char *cp = argv[i];
935
936 if (*cp == '-') {
937 clear = 1;
938 cp++;
939 }
940
941#define SETFLAG(s, f) \
942 do {\
943 if (strcmp(cp, (s)) == 0) {\
944 if (clear)\
945 newflags &= ~(f);\
946 else\
947 newflags |= (f);\
948 }\
949 } while (0)
950/*
951 * XXX: this macro is not 100% correct, in that it matches "nud" against
952 * "nudbogus". But we just let it go since this is minor.
953 */
954#define SETVALUE(f, v) \
955 do { \
956 char *valptr; \
957 unsigned long newval; \
958 v = 0; /* unspecified */ \
959 if (strncmp(cp, f, strlen(f)) == 0) { \
960 valptr = strchr(cp, '='); \
961 if (valptr == NULL) \
962 err(1, "syntax error in %s field", (f)); \
963 errno = 0; \
964 newval = strtoul(++valptr, NULL, 0); \
965 if (errno) \
966 err(1, "syntax error in %s's value", (f)); \
967 v = newval; \
968 } \
969 } while (0)
970
971 SETFLAG("disabled", ND6_IFF_IFDISABLED);
972 SETFLAG("nud", ND6_IFF_PERFORMNUD);
973#ifdef ND6_IFF_ACCEPT_RTADV
974 SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
975#endif
976#ifdef ND6_IFF_AUTO_LINKLOCAL
977 SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
978#endif
979#ifdef ND6_IFF_NO_PREFER_IFACE
980 SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE);
981#endif
982 SETVALUE("basereachable", ND.basereachable);
983 SETVALUE("retrans", ND.retrans);
984 SETVALUE("curhlim", ND.chlim);
985
986 ND.flags = newflags;
987 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
988 err(1, "ioctl(SIOCSIFINFO_IN6)");
989 /* NOTREACHED */
990 }
991#undef SETFLAG
992#undef SETVALUE
993 }
994
995 if (!ND.initialized) {
996 errx(1, "%s: not initialized yet", ifname);
997 /* NOTREACHED */
998 }
999
1000 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1001 err(1, "ioctl(SIOCGIFINFO_IN6)");
1002 /* NOTREACHED */
1003 }
1004 printf("linkmtu=%d", ND.linkmtu);
1005 printf(", maxmtu=%d", ND.maxmtu);
1006 printf(", curhlim=%d", ND.chlim);
1007 printf(", basereachable=%ds%dms",
1008 ND.basereachable / 1000, ND.basereachable % 1000);
1009 printf(", reachable=%ds", ND.reachable);
1010 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
1011#ifdef IPV6CTL_USETEMPADDR
1012 memset(nullbuf, 0, sizeof(nullbuf));
1013 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
1014 int j;
1015 u_int8_t *rbuf;
1016
1017 for (i = 0; i < 3; i++) {
1018 switch (i) {
1019 case 0:
1020 printf("\nRandom seed(0): ");
1021 rbuf = ND.randomseed0;
1022 break;
1023 case 1:
1024 printf("\nRandom seed(1): ");
1025 rbuf = ND.randomseed1;
1026 break;
1027 case 2:
1028 printf("\nRandom ID: ");
1029 rbuf = ND.randomid;
1030 break;
1031 default:
1032 errx(1, "impossible case for tempaddr display");
1033 }
1034 for (j = 0; j < 8; j++)
1035 printf("%02x", rbuf[j]);
1036 }
1037 }
1038#endif
1039 if (ND.flags) {
1040 printf("\nFlags: ");
1041#ifdef ND6_IFF_IFDISABLED
1042 if ((ND.flags & ND6_IFF_IFDISABLED))
1043 printf("disabled ");
1044#endif
1045 if ((ND.flags & ND6_IFF_PERFORMNUD))
1046 printf("nud ");
1047#ifdef ND6_IFF_ACCEPT_RTADV
1048 if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1049 printf("accept_rtadv ");
1050#endif
1051#ifdef ND6_IFF_AUTO_LINKLOCAL
1052 if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
1053 printf("auto_linklocal ");
1054#endif
1055#ifdef ND6_IFF_NO_PREFER_IFACE
1056 if ((ND.flags & ND6_IFF_NO_PREFER_IFACE))
1057 printf("no_prefer_iface ");
1058#endif
1059 }
1060 putc('\n', stdout);
1061#undef ND
1062
1063 close(s);
1064}
1065
1066#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
1067#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
1068#endif
1069
1070void
1071rtrlist()
1072{
1073#ifdef ICMPV6CTL_ND6_DRLIST
1074 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
1075 char *buf;
1076 struct in6_defrouter *p, *ep;
1077 size_t l;
1078 struct timeval time;
1079
1080 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1081 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1082 /*NOTREACHED*/
1083 }
1084 if (l == 0)
1085 return;
1086 buf = malloc(l);
1087 if (!buf) {
1088 err(1, "malloc");
1089 /*NOTREACHED*/
1090 }
1091 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1092 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1093 /*NOTREACHED*/
1094 }
1095
1096 ep = (struct in6_defrouter *)(buf + l);
1097 for (p = (struct in6_defrouter *)buf; p < ep; p++) {
1098 int rtpref;
1099
1100 if (getnameinfo((struct sockaddr *)&p->rtaddr,
1101 p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1102 (nflag ? NI_NUMERICHOST : 0)) != 0)
1103 strlcpy(host_buf, "?", sizeof(host_buf));
1104
1105 printf("%s if=%s", host_buf,
1106 if_indextoname(p->if_index, ifix_buf));
1107 printf(", flags=%s%s",
1108 p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1109 p->flags & ND_RA_FLAG_OTHER ? "O" : "");
1110 rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
1111 printf(", pref=%s", rtpref_str[rtpref]);
1112
1113 gettimeofday(&time, 0);
1114 if (p->expire == 0)
1115 printf(", expire=Never\n");
1116 else
1117 printf(", expire=%s\n",
1118 sec2str(p->expire - time.tv_sec));
1119 }
1120 free(buf);
1121#else
1122 struct in6_drlist dr;
1123 int s, i;
1124 struct timeval time;
1125
1126 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1127 err(1, "socket");
1128 /* NOTREACHED */
1129 }
1130 bzero(&dr, sizeof(dr));
1131 strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
1132 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1133 err(1, "ioctl(SIOCGDRLST_IN6)");
1134 /* NOTREACHED */
1135 }
1136#define DR dr.defrouter[i]
1137 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
1138 struct sockaddr_in6 sin6;
1139
1140 bzero(&sin6, sizeof(sin6));
1141 sin6.sin6_family = AF_INET6;
1142 sin6.sin6_len = sizeof(sin6);
1143 sin6.sin6_addr = DR.rtaddr;
1144 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1145 sizeof(host_buf), NULL, 0,
1146 (nflag ? NI_NUMERICHOST : 0));
1147
1148 printf("%s if=%s", host_buf,
1149 if_indextoname(DR.if_index, ifix_buf));
1150 printf(", flags=%s%s",
1151 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1152 DR.flags & ND_RA_FLAG_OTHER ? "O" : "");
1153 gettimeofday(&time, 0);
1154 if (DR.expire == 0)
1155 printf(", expire=Never\n");
1156 else
1157 printf(", expire=%s\n",
1158 sec2str(DR.expire - time.tv_sec));
1159 }
1160#undef DR
1161 close(s);
1162#endif
1163}
1164
1165void
1166plist()
1167{
1168#ifdef ICMPV6CTL_ND6_PRLIST
1169 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
1170 char *buf;
1171 struct in6_prefix *p, *ep, *n;
1172 struct sockaddr_in6 *advrtr;
1173 size_t l;
1174 struct timeval time;
1175 const int niflags = NI_NUMERICHOST;
1176 int ninflags = nflag ? NI_NUMERICHOST : 0;
1177 char namebuf[NI_MAXHOST];
1178
1179 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1180 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1181 /*NOTREACHED*/
1182 }
1183 buf = malloc(l);
1184 if (!buf) {
1185 err(1, "malloc");
1186 /*NOTREACHED*/
1187 }
1188 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1189 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1190 /*NOTREACHED*/
1191 }
1192
1193 ep = (struct in6_prefix *)(buf + l);
1194 for (p = (struct in6_prefix *)buf; p < ep; p = n) {
1195 advrtr = (struct sockaddr_in6 *)(p + 1);
1196 n = (struct in6_prefix *)&advrtr[p->advrtrs];
1197
1198 if (getnameinfo((struct sockaddr *)&p->prefix,
1199 p->prefix.sin6_len, namebuf, sizeof(namebuf),
1200 NULL, 0, niflags) != 0)
1201 strlcpy(namebuf, "?", sizeof(namebuf));
1202 printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1203 if_indextoname(p->if_index, ifix_buf));
1204
1205 gettimeofday(&time, 0);
1206 /*
1207 * meaning of fields, especially flags, is very different
1208 * by origin. notify the difference to the users.
1209 */
1210 printf("flags=%s%s%s%s%s",
1211 p->raflags.onlink ? "L" : "",
1212 p->raflags.autonomous ? "A" : "",
1213 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1214 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
1215#ifdef NDPRF_HOME
1216 (p->flags & NDPRF_HOME) != 0 ? "H" : ""
1217#else
1218 ""
1219#endif
1220 );
1221 if (p->vltime == ND6_INFINITE_LIFETIME)
1222 printf(" vltime=infinity");
1223 else
1224 printf(" vltime=%lu", (unsigned long)p->vltime);
1225 if (p->pltime == ND6_INFINITE_LIFETIME)
1226 printf(", pltime=infinity");
1227 else
1228 printf(", pltime=%lu", (unsigned long)p->pltime);
1229 if (p->expire == 0)
1230 printf(", expire=Never");
1231 else if (p->expire >= time.tv_sec)
1232 printf(", expire=%s",
1233 sec2str(p->expire - time.tv_sec));
1234 else
1235 printf(", expired");
1236 printf(", ref=%d", p->refcnt);
1237 printf("\n");
1238 /*
1239 * "advertising router" list is meaningful only if the prefix
1240 * information is from RA.
1241 */
1242 if (p->advrtrs) {
1243 int j;
1244 struct sockaddr_in6 *sin6;
1245
1246 sin6 = advrtr;
1247 printf(" advertised by\n");
1248 for (j = 0; j < p->advrtrs; j++) {
1249 struct in6_nbrinfo *nbi;
1250
1251 if (getnameinfo((struct sockaddr *)sin6,
1252 sin6->sin6_len, namebuf, sizeof(namebuf),
1253 NULL, 0, ninflags) != 0)
1254 strlcpy(namebuf, "?", sizeof(namebuf));
1255 printf(" %s", namebuf);
1256
1257 nbi = getnbrinfo(&sin6->sin6_addr,
1258 p->if_index, 0);
1259 if (nbi) {
1260 switch (nbi->state) {
1261 case ND6_LLINFO_REACHABLE:
1262 case ND6_LLINFO_STALE:
1263 case ND6_LLINFO_DELAY:
1264 case ND6_LLINFO_PROBE:
1265 printf(" (reachable)\n");
1266 break;
1267 default:
1268 printf(" (unreachable)\n");
1269 }
1270 } else
1271 printf(" (no neighbor state)\n");
1272 sin6++;
1273 }
1274 } else
1275 printf(" No advertising router\n");
1276 }
1277 free(buf);
1278#else
1279 struct in6_prlist pr;
1280 int s, i;
1281 struct timeval time;
1282
1283 gettimeofday(&time, 0);
1284
1285 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1286 err(1, "socket");
1287 /* NOTREACHED */
1288 }
1289 bzero(&pr, sizeof(pr));
1290 strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
1291 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1292 err(1, "ioctl(SIOCGPRLST_IN6)");
1293 /* NOTREACHED */
1294 }
1295#define PR pr.prefix[i]
1296 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
1297 struct sockaddr_in6 p6;
1298 char namebuf[NI_MAXHOST];
1299 int niflags;
1300
1301#ifdef NDPRF_ONLINK
1302 p6 = PR.prefix;
1303#else
1304 memset(&p6, 0, sizeof(p6));
1305 p6.sin6_family = AF_INET6;
1306 p6.sin6_len = sizeof(p6);
1307 p6.sin6_addr = PR.prefix;
1308#endif
1309 niflags = NI_NUMERICHOST;
1310 if (getnameinfo((struct sockaddr *)&p6,
1311 sizeof(p6), namebuf, sizeof(namebuf),
1312 NULL, 0, niflags)) {
1313 warnx("getnameinfo failed");
1314 continue;
1315 }
1316 printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1317 if_indextoname(PR.if_index, ifix_buf));
1318
1319 gettimeofday(&time, 0);
1320 /*
1321 * meaning of fields, especially flags, is very different
1322 * by origin. notify the difference to the users.
1323 */
1324#if 0
1325 printf(" %s",
1326 PR.origin == PR_ORIG_RA ? "" : "advertise: ");
1327#endif
1328#ifdef NDPRF_ONLINK
1329 printf("flags=%s%s%s%s%s",
1330 PR.raflags.onlink ? "L" : "",
1331 PR.raflags.autonomous ? "A" : "",
1332 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1333 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
1334#ifdef NDPRF_HOME
1335 (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
1336#else
1337 ""
1338#endif
1339 );
1340#else
1341 printf("flags=%s%s",
1342 PR.raflags.onlink ? "L" : "",
1343 PR.raflags.autonomous ? "A" : "");
1344#endif
1345 if (PR.vltime == ND6_INFINITE_LIFETIME)
1346 printf(" vltime=infinity");
1347 else
1348 printf(" vltime=%lu", PR.vltime);
1349 if (PR.pltime == ND6_INFINITE_LIFETIME)
1350 printf(", pltime=infinity");
1351 else
1352 printf(", pltime=%lu", PR.pltime);
1353 if (PR.expire == 0)
1354 printf(", expire=Never");
1355 else if (PR.expire >= time.tv_sec)
1356 printf(", expire=%s",
1357 sec2str(PR.expire - time.tv_sec));
1358 else
1359 printf(", expired");
1360#ifdef NDPRF_ONLINK
1361 printf(", ref=%d", PR.refcnt);
1362#endif
1363#if 0
1364 switch (PR.origin) {
1365 case PR_ORIG_RA:
1366 printf(", origin=RA");
1367 break;
1368 case PR_ORIG_RR:
1369 printf(", origin=RR");
1370 break;
1371 case PR_ORIG_STATIC:
1372 printf(", origin=static");
1373 break;
1374 case PR_ORIG_KERNEL:
1375 printf(", origin=kernel");
1376 break;
1377 default:
1378 printf(", origin=?");
1379 break;
1380 }
1381#endif
1382 printf("\n");
1383 /*
1384 * "advertising router" list is meaningful only if the prefix
1385 * information is from RA.
1386 */
1387 if (0 && /* prefix origin is almost obsolted */
1388 PR.origin != PR_ORIG_RA)
1389 ;
1390 else if (PR.advrtrs) {
1391 int j;
1392 printf(" advertised by\n");
1393 for (j = 0; j < PR.advrtrs; j++) {
1394 struct sockaddr_in6 sin6;
1395 struct in6_nbrinfo *nbi;
1396
1397 bzero(&sin6, sizeof(sin6));
1398 sin6.sin6_family = AF_INET6;
1399 sin6.sin6_len = sizeof(sin6);
1400 sin6.sin6_addr = PR.advrtr[j];
1401 sin6.sin6_scope_id = PR.if_index; /* XXX */
1402 getnameinfo((struct sockaddr *)&sin6,
1403 sin6.sin6_len, host_buf,
1404 sizeof(host_buf), NULL, 0,
1405 (nflag ? NI_NUMERICHOST : 0));
1406 printf(" %s", host_buf);
1407
1408 nbi = getnbrinfo(&sin6.sin6_addr,
1409 PR.if_index, 0);
1410 if (nbi) {
1411 switch (nbi->state) {
1412 case ND6_LLINFO_REACHABLE:
1413 case ND6_LLINFO_STALE:
1414 case ND6_LLINFO_DELAY:
1415 case ND6_LLINFO_PROBE:
1416 printf(" (reachable)\n");
1417 break;
1418 default:
1419 printf(" (unreachable)\n");
1420 }
1421 } else
1422 printf(" (no neighbor state)\n");
1423 }
1424 if (PR.advrtrs > DRLSTSIZ)
1425 printf(" and %d routers\n",
1426 PR.advrtrs - DRLSTSIZ);
1427 } else
1428 printf(" No advertising router\n");
1429 }
1430#undef PR
1431 close(s);
1432#endif
1433}
1434
1435void
1436pfx_flush()
1437{
1438 char dummyif[IFNAMSIZ+8];
1439 int s;
1440
1441 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1442 err(1, "socket");
1443 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1444 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1445 err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1446}
1447
1448void
1449rtr_flush()
1450{
1451 char dummyif[IFNAMSIZ+8];
1452 int s;
1453
1454 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1455 err(1, "socket");
1456 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1457 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1458 err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1459
1460 close(s);
1461}
1462
1463void
1464harmonize_rtr()
1465{
1466 char dummyif[IFNAMSIZ+8];
1467 int s;
1468
1469 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1470 err(1, "socket");
1471 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1472 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1473 err(1, "ioctl(SIOCSNDFLUSH_IN6)");
1474
1475 close(s);
1476}
1477
1478#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
1479static void
1480setdefif(ifname)
1481 char *ifname;
1482{
1483 struct in6_ndifreq ndifreq;
1484 unsigned int ifindex;
1485
1486 if (strcasecmp(ifname, "delete") == 0)
1487 ifindex = 0;
1488 else {
1489 if ((ifindex = if_nametoindex(ifname)) == 0)
1490 err(1, "failed to resolve i/f index for %s", ifname);
1491 }
1492
1493 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1494 err(1, "socket");
1495
1496 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1497 ndifreq.ifindex = ifindex;
1498
1499 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1500 err(1, "ioctl(SIOCSDEFIFACE_IN6)");
1501
1502 close(s);
1503}
1504
1505static void
1506getdefif()
1507{
1508 struct in6_ndifreq ndifreq;
1509 char ifname[IFNAMSIZ+8];
1510
1511 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1512 err(1, "socket");
1513
1514 memset(&ndifreq, 0, sizeof(ndifreq));
1515 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1516
1517 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1518 err(1, "ioctl(SIOCGDEFIFACE_IN6)");
1519
1520 if (ndifreq.ifindex == 0)
1521 printf("No default interface.\n");
1522 else {
1523 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1524 err(1, "failed to resolve ifname for index %lu",
1525 ndifreq.ifindex);
1526 printf("ND default interface = %s\n", ifname);
1527 }
1528
1529 close(s);
1530}
1531#endif
1532
1533static char *
1534sec2str(total)
1535 time_t total;
1536{
1537 static char result[256];
1538 int days, hours, mins, secs;
1539 int first = 1;
1540 char *p = result;
1541 char *ep = &result[sizeof(result)];
1542 int n;
1543
1544 days = total / 3600 / 24;
1545 hours = (total / 3600) % 24;
1546 mins = (total / 60) % 60;
1547 secs = total % 60;
1548
1549 if (days) {
1550 first = 0;
1551 n = snprintf(p, ep - p, "%dd", days);
1552 if (n < 0 || n >= ep - p)
1553 return "?";
1554 p += n;
1555 }
1556 if (!first || hours) {
1557 first = 0;
1558 n = snprintf(p, ep - p, "%dh", hours);
1559 if (n < 0 || n >= ep - p)
1560 return "?";
1561 p += n;
1562 }
1563 if (!first || mins) {
1564 first = 0;
1565 n = snprintf(p, ep - p, "%dm", mins);
1566 if (n < 0 || n >= ep - p)
1567 return "?";
1568 p += n;
1569 }
1570 snprintf(p, ep - p, "%ds", secs);
1571
1572 return(result);
1573}
1574
1575/*
1576 * Print the timestamp
1577 * from tcpdump/util.c
1578 */
1579static void
1580ts_print(tvp)
1581 const struct timeval *tvp;
1582{
1583 int s;
1584
1585 /* Default */
1586 s = (tvp->tv_sec + thiszone) % 86400;
1587 (void)printf("%02d:%02d:%02d.%06u ",
1588 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
1589}
1590
1591#undef NEXTADDR