Print this page
OS-4807 arp(1M) and ndp(1M) should use zone_get_nroot()
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
+++ new/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2015 Joyent, Inc. All rights reserved.
14 14 */
15 15
16 16 /*
17 17 * ndp - display and manipulate Neighbor Cache Entries from NDP
18 18 */
19 19
20 20 #include <stdio.h>
21 21 #include <stdarg.h>
22 22 #include <signal.h>
23 23 #include <time.h>
24 24 #include <err.h>
25 25 #include <errno.h>
26 26 #include <stdlib.h>
27 27 #include <strings.h>
28 28 #include <unistd.h>
29 29 #include <libgen.h>
30 30 #include <sys/ioctl.h>
31 31 #include <sys/types.h>
32 32 #include <wait.h>
|
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
33 33 #include <sys/mac.h>
34 34 #include <sys/socket.h>
35 35 #include <sys/sockio.h>
36 36 #include <netdb.h>
37 37 #include <net/if_types.h>
38 38 #include <netinet/in.h>
39 39 #include <arpa/inet.h>
40 40 #include <inet/ip.h>
41 41 #include <net/if_dl.h>
42 42 #include <net/route.h>
43 +#include <zone.h>
43 44
44 45 typedef struct sockaddr_in6 sin6_t;
45 46
46 47 #define BUF_SIZE 2048
47 48 typedef struct rtmsg_pkt {
48 49 struct rt_msghdr m_rtm;
49 50 char m_space[BUF_SIZE];
50 51 } rtmsg_pkt_t;
51 52
52 53 enum ndp_action {
53 54 NDP_A_DEFAULT,
54 55 NDP_A_GET, /* Show a single NDP entry */
55 56 NDP_A_GET_ALL, /* Show NDP entries */
56 57 NDP_A_GET_FOREVER, /* Repeatedly show entries */
57 58 NDP_A_DELETE, /* Delete an NDP entry */
58 59 NDP_A_SET_NCE, /* Set NDP entry */
59 60 NDP_A_SET_FILE /* Read in & set NDP entries */
60 61 };
61 62
62 63 typedef int (ndp_addr_f)(int, struct lifreq *, void *);
63 64 typedef void (ndp_void_f)(void);
64 65
65 66 static void ndp_usage(const char *, ...);
66 67 static void ndp_fatal(const char *, ...);
67 68 static void ndp_badflag(enum ndp_action);
68 69 static void ndp_missingarg(char);
69 70
70 71 static void ndp_run_in_child(ndp_void_f *);
71 72 static void ndp_do_run(void);
72 73 static void ndp_setup_handler(sigset_t *);
73 74 static void ndp_start_timer(time_t period);
74 75 static void ndp_run_periodically(time_t, ndp_void_f *);
75 76
76 77 static int ndp_salen(const struct sockaddr *sa);
77 78 static int ndp_extract_sockaddrs(struct rt_msghdr *, struct sockaddr **,
78 79 struct sockaddr **, struct sockaddr **, struct sockaddr **,
79 80 struct sockaddr_dl **);
80 81 static int ndp_rtmsg_get(int, rtmsg_pkt_t *, struct sockaddr *);
81 82 static int ndp_find_interface(int, struct sockaddr *, char *, int);
82 83
83 84 static int ndp_initialize_lifreq(int, struct lifreq *, struct sockaddr *);
84 85 static int ndp_host_enumerate(char *, ndp_addr_f *, void *);
85 86
86 87 static int ndp_display(struct lifreq *);
87 88 static int ndp_display_missing(struct lifreq *);
|
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
88 89 static void ndp_lifr2ip(struct lifreq *, char *, int);
89 90
90 91 static int ndp_get(int, struct lifreq *, void *);
91 92 static void ndp_get_all(void);
92 93 static int ndp_delete(int, struct lifreq *, void *);
93 94 static int ndp_set(int, struct lifreq *, void *);
94 95 static int ndp_set_nce(char *, char *, char *[], int);
95 96 static int ndp_set_file(char *);
96 97
97 98 static char *ndp_iface = NULL;
98 -static char *netstat_path = "/usr/bin/netstat";
99 99 static pid_t ndp_pid;
100 100 static boolean_t ndp_noresolve = B_FALSE; /* Don't lookup addresses */
101 101 static boolean_t ndp_run = B_TRUE;
102 102
103 103 #define MAX_ATTEMPTS 5
104 104 #define MAX_OPTS 5
105 105 #define WORDSEPS " \t\r\n"
106 +#define NETSTAT_PATH "/usr/bin/netstat"
106 107
107 108 /*
108 109 * Macros borrowed from route(1M) for working with PF_ROUTE messages
109 110 */
110 111 #define RT_ADVANCE(x, n) ((x) += ndp_salen(n))
111 112 #define RT_NEXTADDR(cp, w, u) \
112 113 l = ndp_salen(u); \
113 114 (void) memmove(cp, u, l); \
114 115 cp += l;
115 116
116 117 /*
117 118 * Print an error to stderr and then exit non-zero.
118 119 */
119 120 static void
120 121 ndp_fatal(const char *format, ...)
121 122 {
122 123 va_list ap;
123 124
124 125 va_start(ap, format);
125 126 vwarnx(format, ap);
126 127 va_end(ap);
127 128 exit(EXIT_FAILURE);
128 129 }
129 130
130 131 /*
131 132 * Print out the command usage to stderr, along with any reason why it's being
132 133 * printed, and then exit non-zero.
133 134 */
134 135 static void
135 136 ndp_usage(const char *reason, ...)
136 137 {
137 138 va_list ap;
138 139 const char *ndp_progname = getprogname();
139 140
140 141 if (reason != NULL) {
141 142 va_start(ap, reason);
142 143 (void) fprintf(stderr, "%s: ", ndp_progname);
143 144 (void) vfprintf(stderr, reason, ap);
144 145 (void) fprintf(stderr, "\n");
145 146 va_end(ap);
146 147 }
147 148
148 149 (void) fprintf(stderr,
149 150 "Usage: %s [-n] [-i iface] hostname\n"
150 151 " %s [-n] [-i iface] -s nodeaddr etheraddr [temp] [proxy]\n"
151 152 " %s [-n] [-i iface] -d nodeaddr\n"
152 153 " %s [-n] [-i iface] -f filename\n"
153 154 " %s [-n] -a\n"
154 155 " %s [-n] -A period\n",
155 156 ndp_progname, ndp_progname, ndp_progname,
156 157 ndp_progname, ndp_progname, ndp_progname);
157 158 exit(EXIT_FAILURE);
158 159 }
159 160
160 161 static void
161 162 ndp_badflag(enum ndp_action action)
162 163 {
163 164 switch (action) {
164 165 case NDP_A_DEFAULT:
165 166 case NDP_A_GET:
166 167 ndp_usage("Already going to print an entry, "
167 168 "but extra -%c given", optopt);
168 169 break;
169 170 case NDP_A_GET_ALL:
170 171 ndp_usage("Already going to print all entries (-a), "
171 172 "but extra -%c given", optopt);
172 173 break;
173 174 case NDP_A_GET_FOREVER:
174 175 ndp_usage("Already going to repeatedly print all entries (-A), "
175 176 "but extra -%c given", optopt);
176 177 break;
177 178 case NDP_A_DELETE:
178 179 ndp_usage("Already going to delete an entry (-d), "
179 180 "but extra -%c given", optopt);
180 181 break;
181 182 case NDP_A_SET_NCE:
182 183 ndp_usage("Already going to set an entry (-s), "
183 184 "but extra -%c given", optopt);
184 185 break;
185 186 case NDP_A_SET_FILE:
186 187 ndp_usage("Already going to set from file (-f), "
187 188 "but extra -%c given", optopt);
188 189 break;
189 190 }
190 191 }
191 192
192 193 static void
193 194 ndp_missingarg(char flag)
194 195 {
195 196 switch (flag) {
196 197 case 'A':
197 198 ndp_usage("Missing time period after -%c", flag);
198 199 break;
199 200 case 'd':
200 201 ndp_usage("Missing node name after -%c", flag);
201 202 break;
202 203 case 'f':
203 204 ndp_usage("Missing filename after -%c", flag);
204 205 break;
205 206 case 's':
206 207 ndp_usage("Missing node name after -%c", flag);
207 208 break;
208 209 case 'i':
209 210 ndp_usage("Missing interface name after -%c", flag);
210 211 break;
211 212 default:
212 213 ndp_usage("Missing option argument after -%c", flag);
213 214 break;
214 215 }
215 216 }
216 217
217 218 /*
218 219 * Run a function that's going to exec in a child process, and don't return
219 220 * until it exits.
220 221 */
221 222 static void
222 223 ndp_run_in_child(ndp_void_f *func)
223 224 {
224 225 pid_t child_pid;
225 226 int childstat = 0, status = 0;
226 227
227 228 child_pid = fork();
228 229 if (child_pid == (pid_t)-1) {
229 230 ndp_fatal("Unable to fork: %s", strerror(errno));
230 231 } else if (child_pid == (pid_t)0) {
231 232 func();
232 233 exit(EXIT_FAILURE);
233 234 }
234 235
235 236 while (waitpid(child_pid, &childstat, 0) == -1) {
236 237 if (errno == EINTR)
237 238 continue;
238 239
239 240 ndp_fatal("Failed to wait on child: %s", strerror(errno));
240 241 }
241 242
242 243 status = WEXITSTATUS(childstat);
243 244 if (status != 0) {
244 245 ndp_fatal("Child process exited with %d", status);
245 246 }
246 247 }
247 248
248 249 /*
249 250 * SIGALRM handler to schedule a run.
250 251 */
251 252 static void
252 253 ndp_do_run(void)
253 254 {
254 255 ndp_run = B_TRUE;
255 256 }
256 257
257 258
258 259 /*
259 260 * Prepare signal masks, and install the SIGALRM handler. Return old signal
260 261 * masks through the first argument.
261 262 */
262 263 static void
263 264 ndp_setup_handler(sigset_t *oset)
264 265 {
265 266 struct sigaction sa;
266 267
267 268 /*
268 269 * Mask off SIGALRM so we only trigger the handler when we're ready
269 270 * using sigsuspend(3C), in case the child process takes longer to
270 271 * run than the alarm interval.
271 272 */
272 273 if (sigprocmask(0, NULL, oset) != 0) {
273 274 ndp_fatal("Unable to set signal mask: %s", strerror(errno));
274 275 }
275 276
276 277 if (sighold(SIGALRM) != 0) {
277 278 ndp_fatal("Unable to add SIGALRM to signal mask: %s",
278 279 strerror(errno));
279 280 }
280 281
281 282 sa.sa_flags = 0;
282 283 sa.sa_handler = ndp_do_run;
283 284
284 285 if (sigemptyset(&sa.sa_mask) != 0) {
285 286 ndp_fatal("Unable to prepare empty signal set: %s",
286 287 strerror(errno));
287 288 }
288 289
289 290 if (sigaction(SIGALRM, &sa, NULL) != 0) {
290 291 ndp_fatal("Unable to install timer handler: %s",
291 292 strerror(errno));
292 293 }
293 294 }
294 295
295 296 /*
296 297 * Start the printing timer.
297 298 */
298 299 static void
299 300 ndp_start_timer(time_t period)
300 301 {
301 302 timer_t timer;
302 303 struct itimerspec interval;
303 304 interval.it_value.tv_sec = interval.it_interval.tv_sec = period;
304 305 interval.it_value.tv_nsec = interval.it_interval.tv_nsec = 0;
305 306
306 307 if (timer_create(CLOCK_REALTIME, NULL, &timer) != 0) {
307 308 ndp_fatal("Unable to create timer: %s", strerror(errno));
308 309 }
309 310
310 311 if (timer_settime(timer, 0, &interval, NULL) != 0) {
311 312 ndp_fatal("Unable to set time on timer: %s", strerror(errno));
312 313 }
313 314 }
314 315
315 316
316 317 /*
317 318 * Run a given function forever periodically in a child process.
318 319 */
319 320 static void
320 321 ndp_run_periodically(time_t period, ndp_void_f *func)
321 322 {
322 323 sigset_t oset;
323 324
324 325 ndp_setup_handler(&oset);
325 326 ndp_start_timer(period);
326 327
327 328 do {
328 329 if (ndp_run) {
329 330 ndp_run = B_FALSE;
330 331 ndp_run_in_child(func);
331 332 }
332 333 (void) sigsuspend(&oset);
333 334 } while (errno == EINTR);
334 335
335 336 /*
336 337 * Only an EFAULT should get us here. Abort so we get a core dump.
337 338 */
338 339 warnx("Failure while waiting on timer: %s", strerror(errno));
339 340 abort();
340 341 }
341 342
342 343 /*
343 344 * Given an address, return its size.
344 345 */
345 346 static int
346 347 ndp_salen(const struct sockaddr *sa)
347 348 {
348 349 switch (sa->sa_family) {
349 350 case AF_INET:
350 351 return (sizeof (struct sockaddr_in));
351 352 case AF_LINK:
352 353 return (sizeof (struct sockaddr_dl));
353 354 case AF_INET6:
354 355 return (sizeof (struct sockaddr_in6));
355 356 default:
356 357 warnx("Unrecognized sockaddr with address family %d!",
357 358 sa->sa_family);
358 359 abort();
359 360 }
360 361 /*NOTREACHED*/
361 362 }
362 363
363 364 /*
364 365 * Extract all socket addresses from a routing message, and return them
365 366 * through the pointers given as arguments to ndp_extract_sockaddrs. None
366 367 * of the pointers should be null.
367 368 */
368 369 static int
369 370 ndp_extract_sockaddrs(struct rt_msghdr *rtm, struct sockaddr **dst,
370 371 struct sockaddr **gate, struct sockaddr **mask, struct sockaddr **src,
371 372 struct sockaddr_dl **ifp)
372 373 {
373 374 struct sockaddr *sa;
374 375 char *cp;
375 376 int i;
376 377
377 378 if (rtm->rtm_version != RTM_VERSION) {
378 379 warnx("Routing message version %d not understood",
379 380 rtm->rtm_version);
380 381 return (-1);
381 382 }
382 383
383 384 if (rtm->rtm_errno != 0) {
384 385 warnx("Routing message couldn't be processed: %s",
385 386 strerror(rtm->rtm_errno));
386 387 return (-1);
387 388 }
388 389
389 390 cp = ((char *)(rtm + 1));
390 391 if (rtm->rtm_addrs != 0) {
391 392 for (i = 1; i != 0; i <<= 1) {
392 393 if ((i & rtm->rtm_addrs) == 0)
393 394 continue;
394 395
395 396 /*LINTED*/
396 397 sa = (struct sockaddr *)cp;
397 398 switch (i) {
398 399 case RTA_DST:
399 400 *dst = sa;
400 401 break;
401 402 case RTA_GATEWAY:
402 403 *gate = sa;
403 404 break;
404 405 case RTA_NETMASK:
405 406 *mask = sa;
406 407 break;
407 408 case RTA_IFP:
408 409 if (sa->sa_family == AF_LINK &&
409 410 ((struct sockaddr_dl *)sa)->sdl_nlen != 0)
410 411 *ifp = (struct sockaddr_dl *)sa;
411 412 break;
412 413 case RTA_SRC:
413 414 *src = sa;
414 415 break;
415 416 }
416 417 RT_ADVANCE(cp, sa);
417 418 }
418 419 }
419 420
420 421 return (0);
421 422 }
422 423
423 424 /*
424 425 * Given an IPv6 address, use routing information to look up
425 426 * the destination and interface it would pass through.
426 427 */
427 428 static int
428 429 ndp_rtmsg_get(int fd, rtmsg_pkt_t *msg, struct sockaddr *sin6p)
429 430 {
430 431 static int seq = 0;
431 432 struct sockaddr_dl sdl;
432 433 int mlen, l;
433 434 char ipaddr[INET6_ADDRSTRLEN];
434 435 char *cp = msg->m_space;
435 436 struct rt_msghdr *m_rtm = &msg->m_rtm;
436 437
437 438 bzero(msg, sizeof (rtmsg_pkt_t));
438 439 bzero(&sdl, sizeof (struct sockaddr_dl));
439 440
440 441 m_rtm->rtm_type = RTM_GET;
441 442 m_rtm->rtm_version = RTM_VERSION;
442 443 m_rtm->rtm_seq = ++seq;
443 444 m_rtm->rtm_addrs = RTA_DST | RTA_IFP;
444 445 m_rtm->rtm_msglen = sizeof (rtmsg_pkt_t);
445 446
446 447 /* Place the address we're looking up after the header */
447 448 RT_NEXTADDR(cp, RTA_DST, sin6p);
448 449
449 450 /* Load an empty link-level address, so we get an interface back */
450 451 sdl.sdl_family = AF_LINK;
451 452 RT_NEXTADDR(cp, RTA_IFP, (struct sockaddr *)&sdl);
452 453
453 454 m_rtm->rtm_msglen = cp - (char *)msg;
454 455
455 456 if ((mlen = write(fd, (char *)msg, m_rtm->rtm_msglen)) < 0) {
456 457 if (errno == ESRCH) {
457 458 /*LINTED*/
458 459 if (inet_ntop(AF_INET6, &((sin6_t *)sin6p)->sin6_addr,
459 460 ipaddr, sizeof (ipaddr)) == NULL) {
460 461 (void) snprintf(ipaddr, sizeof (ipaddr),
461 462 "(failed to format IP)");
462 463 };
463 464 warnx("An appropriate interface for the address %s "
464 465 "is not in the routing table; use -i to force an "
465 466 "interface", ipaddr);
466 467 return (-1);
467 468 } else {
468 469 warnx("Failed to send routing message: %s",
469 470 strerror(errno));
470 471 return (-1);
471 472 }
472 473 } else if (mlen < (int)m_rtm->rtm_msglen) {
473 474 warnx("Failed to write all bytes to routing socket");
474 475 return (-1);
475 476 }
476 477
477 478 /*
478 479 * Keep reading routing messages until we find the response to the one
479 480 * we just sent. Note that we depend on the sequence number being unique
480 481 * to the running program.
481 482 */
482 483 do {
483 484 mlen = read(fd, (char *)msg, sizeof (rtmsg_pkt_t));
484 485 } while (mlen > 0 &&
485 486 (m_rtm->rtm_seq != seq || m_rtm->rtm_pid != ndp_pid));
486 487 if (mlen < 0) {
487 488 warnx("Failed to read from routing socket: %s",
488 489 strerror(errno));
489 490 return (-1);
490 491 }
491 492
492 493 return (0);
493 494 }
494 495
495 496 /*
496 497 * Find the interface that the IPv6 address would be routed through, and store
497 498 * the name of the interface in the buffer passed in.
498 499 */
499 500 static int
500 501 ndp_find_interface(int fd, struct sockaddr *sin6p, char *buf, int buflen)
501 502 {
502 503 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL;
503 504 struct sockaddr_dl *ifp = NULL;
504 505 rtmsg_pkt_t msg;
505 506
506 507 if (ndp_rtmsg_get(fd, &msg, sin6p) != 0) {
507 508 return (-1);
508 509 }
509 510
510 511 if (ndp_extract_sockaddrs(&msg.m_rtm, &dst, &gate,
511 512 &mask, &src, &ifp) != 0) {
512 513 return (-1);
513 514 }
514 515
515 516 if (ifp == NULL) {
516 517 warnx("Unable to find appropriate interface for address");
517 518 return (-1);
518 519 } else {
519 520 if (ifp->sdl_nlen >= buflen) {
520 521 warnx("The interface name \"%.*s\" is too big for the "
521 522 "available buffer", ifp->sdl_nlen, ifp->sdl_data);
522 523 return (-1);
523 524 } else {
524 525 (void) snprintf(buf, buflen, "%.*s", ifp->sdl_nlen,
525 526 ifp->sdl_data);
526 527 }
527 528 }
528 529
529 530 return (0);
530 531 }
531 532
532 533 /*
533 534 * Zero out a lifreq struct for a SIOCLIF*ND ioctl, set the address, and fetch
534 535 * the appropriate interface using the given routing socket.
535 536 */
536 537 static int
537 538 ndp_initialize_lifreq(int route, struct lifreq *lifrp, struct sockaddr *sap)
538 539 {
539 540 struct sockaddr_storage *lnr_addr;
540 541 /* LINTED E_BAD_PTR_CAST_ALIGN */
541 542 struct sockaddr_in6 *sin6p = (sin6_t *)sap;
542 543 char *lifr_name = lifrp->lifr_name;
543 544
544 545 bzero(lifrp, sizeof (struct lifreq));
545 546 lnr_addr = &lifrp->lifr_nd.lnr_addr;
546 547
547 548 if (ndp_iface != NULL) {
548 549 (void) strlcpy(lifr_name, ndp_iface, LIFNAMSIZ);
549 550 } else if (sin6p->sin6_scope_id != 0) {
550 551 int zone_id = sin6p->sin6_scope_id;
551 552 if (if_indextoname(zone_id, lifr_name) == NULL) {
552 553 warnx("Invalid zone identifier: %d", zone_id);
553 554 return (-1);
554 555 }
555 556 } else if (IN6_IS_ADDR_LINKSCOPE(&sin6p->sin6_addr)) {
556 557 warnx("Link-scope addresses should specify an interface with "
557 558 "a zone ID, or with -i.");
558 559 return (-1);
559 560 } else {
560 561 if (ndp_find_interface(route, sap, lifr_name, LIFNAMSIZ) != 0)
561 562 return (-1);
562 563 }
563 564
564 565 (void) memcpy(lnr_addr, sap, sizeof (struct sockaddr_storage));
565 566
566 567 return (0);
567 568 }
568 569
569 570 /*
570 571 * Take a host identifier, find the corresponding IPv6 addresses and then pass
571 572 * them to the specified function, along with any desired data.
572 573 */
573 574 static int
574 575 ndp_host_enumerate(char *host, ndp_addr_f *addr_func, void *data)
575 576 {
576 577 struct lifreq lifr;
577 578 struct addrinfo hints, *serverinfo, *p;
578 579 int err, attempts = 0;
579 580 int inet6, route;
580 581
581 582 bzero(&hints, sizeof (struct addrinfo));
582 583 hints.ai_family = AF_INET6;
583 584 hints.ai_protocol = IPPROTO_IPV6;
584 585
585 586 while (attempts < MAX_ATTEMPTS) {
586 587 err = getaddrinfo(host, NULL, &hints, &serverinfo);
587 588
588 589 if (err == 0) {
589 590 break;
590 591 } else if (err == EAI_AGAIN) {
591 592 attempts++;
592 593 } else {
593 594 warnx("Unable to lookup %s: %s", host,
594 595 gai_strerror(err));
595 596 return (-1);
596 597 }
597 598 }
598 599
599 600 if (attempts == MAX_ATTEMPTS) {
600 601 warnx("Failed multiple times to lookup %s", host);
601 602 return (-1);
602 603 }
603 604
604 605 inet6 = socket(PF_INET6, SOCK_DGRAM, 0);
605 606 if (inet6 < 0) {
606 607 warnx("Failed to open IPv6 socket: %s", strerror(errno));
607 608 err = -1;
608 609 }
609 610
610 611 route = socket(PF_ROUTE, SOCK_RAW, 0);
611 612 if (route < 0) {
612 613 warnx("Failed to open routing socket: %s", strerror(errno));
613 614 err = -1;
614 615 }
615 616
616 617 if (err == 0) {
617 618 for (p = serverinfo; p != NULL; p = p->ai_next) {
618 619 if (ndp_initialize_lifreq(route, &lifr, p->ai_addr)
619 620 != 0) {
620 621 err = -1;
621 622 continue;
622 623 }
623 624
624 625 if (addr_func(inet6, &lifr, data) != 0) {
625 626 err = -1;
626 627 continue;
627 628 }
628 629 }
629 630 }
630 631
631 632 if (close(route) != 0) {
632 633 warnx("Failed to close routing socket: %s", strerror(errno));
633 634 err = -1;
634 635 }
635 636
636 637 if (close(inet6) != 0) {
637 638 warnx("Failed to close IPv6 socket: %s", strerror(errno));
638 639 err = -1;
639 640 }
640 641
641 642 /* Clean up linked list */
642 643 freeaddrinfo(serverinfo);
643 644
644 645 return (err);
645 646 }
646 647
647 648 static int
648 649 ndp_display(struct lifreq *lifrp)
649 650 {
650 651 struct sockaddr_in6 *lnr_addr;
651 652 char ipaddr[INET6_ADDRSTRLEN];
652 653 char *lladdr = NULL;
653 654 char hostname[NI_MAXHOST];
654 655 int flags, gni_flags;
655 656
656 657 lnr_addr = (struct sockaddr_in6 *)&lifrp->lifr_nd.lnr_addr;
657 658 flags = lifrp->lifr_nd.lnr_flags;
658 659
659 660 if (inet_ntop(AF_INET6, &lnr_addr->sin6_addr, ipaddr,
660 661 sizeof (ipaddr)) == NULL) {
661 662 warnx("Couldn't convert IPv6 address to string: %s",
662 663 strerror(errno));
663 664 return (-1);
664 665 };
665 666
666 667 if ((lladdr = _link_ntoa((uchar_t *)lifrp->lifr_nd.lnr_hdw_addr,
667 668 NULL, lifrp->lifr_nd.lnr_hdw_len, IFT_ETHER)) == NULL) {
668 669 warnx("Couldn't convert link-layer address to string: %s",
669 670 strerror(errno));
670 671 return (-1);
671 672 }
672 673
673 674 gni_flags = ndp_noresolve ? NI_NUMERICHOST : 0;
674 675
675 676 if (getnameinfo((struct sockaddr *)lnr_addr, sizeof (sin6_t), hostname,
676 677 sizeof (hostname), NULL, 0, gni_flags) != 0) {
677 678 warnx("Unable to lookup hostname for %s", ipaddr);
678 679 free(lladdr);
679 680 return (-1);
680 681 }
681 682
682 683 (void) printf("%s (%s) at %s", ipaddr, hostname, lladdr);
683 684
684 685 if (flags & NDF_ISROUTER_ON) {
685 686 (void) printf(" router");
686 687 }
687 688
688 689 if (flags & NDF_ANYCAST_ON) {
689 690 (void) printf(" any");
690 691 }
691 692
692 693 if (!(flags & NDF_STATIC)) {
693 694 (void) printf(" temp");
694 695 }
695 696
696 697 if (flags & NDF_PROXY_ON) {
697 698 (void) printf(" proxy");
698 699 }
699 700
700 701 (void) printf("\n");
701 702
702 703 free(lladdr);
703 704 return (0);
704 705 }
705 706
706 707 static int
707 708 ndp_display_missing(struct lifreq *lifrp)
708 709 {
709 710 struct sockaddr_in6 *lnr_addr;
710 711 char ipaddr[INET6_ADDRSTRLEN];
711 712 char hostname[NI_MAXHOST];
712 713 int flags = ndp_noresolve ? NI_NUMERICHOST : 0;
713 714 lnr_addr = (struct sockaddr_in6 *)&lifrp->lifr_nd.lnr_addr;
714 715
715 716 if (inet_ntop(AF_INET6, &lnr_addr->sin6_addr, ipaddr,
716 717 sizeof (ipaddr)) == NULL) {
717 718 warnx("Couldn't convert IPv6 address to string: %s",
718 719 strerror(errno));
719 720 return (-1);
720 721 };
721 722
722 723 if (getnameinfo((struct sockaddr *)lnr_addr, sizeof (sin6_t), hostname,
723 724 sizeof (hostname), NULL, 0, flags) != 0) {
724 725 warnx("Unable to lookup hostname for %s", ipaddr);
725 726 return (-1);
726 727 }
727 728
728 729 (void) printf("%s (%s) -- no entry\n", ipaddr, hostname);
729 730 return (0);
730 731 }
731 732
732 733 static void
733 734 ndp_lifr2ip(struct lifreq *lifrp, char *ipaddr, int buflen)
734 735 {
735 736 sin6_t *lnr_addr = (sin6_t *)&lifrp->lifr_nd.lnr_addr;
736 737 if (inet_ntop(AF_INET6, &lnr_addr->sin6_addr, ipaddr,
737 738 buflen) == NULL) {
738 739 (void) snprintf(ipaddr, buflen, "(failed to format IP)");
739 740 };
740 741 }
741 742
742 743 /*
743 744 * Perform a SIOCLIFGETND and print out information about it
744 745 */
745 746 /*ARGSUSED*/
746 747 static int
747 748 ndp_get(int fd, struct lifreq *lifrp, void *unused)
748 749 {
749 750 char ipaddr[INET6_ADDRSTRLEN];
750 751 if (ioctl(fd, SIOCLIFGETND, lifrp) < 0) {
751 752 if (errno == ESRCH) {
752 753 return (ndp_display_missing(lifrp));
753 754 } else {
754 755 ndp_lifr2ip(lifrp, ipaddr, sizeof (ipaddr));
755 756 warnx("Couldn't lookup %s: %s",
756 757 ipaddr, strerror(errno));
757 758 return (-1);
758 759 }
759 760 }
|
↓ open down ↓ |
644 lines elided |
↑ open up ↑ |
760 761
761 762 return (ndp_display(lifrp));
762 763 }
763 764
764 765 /*
765 766 * Print out all NDP entries
766 767 */
767 768 static void
768 769 ndp_get_all(void)
769 770 {
771 + char netstat_path[MAXPATHLEN];
772 + const char *zroot = zone_get_nroot();
773 +
774 + (void) snprintf(netstat_path, sizeof (netstat_path), "%s%s", zroot != NULL ?
775 + zroot : "", NETSTAT_PATH);
776 +
770 777 (void) execl(netstat_path, "netstat",
771 778 (ndp_noresolve ? "-np" : "-p"),
772 779 "-f", "inet6", (char *)0);
773 780 ndp_fatal("Coudn't exec %s: %s", netstat_path, strerror(errno));
774 781 }
775 782
776 783 /*
777 784 * Perform a SIOCLIFDELND ioctl
778 785 */
779 786 /*ARGSUSED*/
780 787 static int
781 788 ndp_delete(int fd, struct lifreq *lifrp, void *unused)
782 789 {
783 790 char ipaddr[INET6_ADDRSTRLEN];
784 791
785 792 if (ioctl(fd, SIOCLIFDELND, lifrp) < 0) {
786 793 ndp_lifr2ip(lifrp, ipaddr, sizeof (ipaddr));
787 794 if (errno == ESRCH) {
788 795 warnx("No entry for %s", ipaddr);
789 796 return (-1);
790 797 } else if (errno == EPERM) {
791 798 warnx("Permission denied, "
792 799 "could not delete entry for %s", ipaddr);
793 800 return (-1);
794 801 } else {
795 802 warnx("Couldn't delete mapping for %s: %s",
796 803 ipaddr, strerror(errno));
797 804 return (-1);
798 805 }
799 806 }
800 807
801 808 return (0);
802 809 }
803 810
804 811 /*
805 812 * Perform a SIOCLIFSETND ioctl using properties from the example structure.
806 813 */
807 814 static int
808 815 ndp_set(int fd, struct lifreq *lifrp, void *data)
809 816 {
810 817 char ipaddr[INET6_ADDRSTRLEN];
811 818 const lif_nd_req_t *nd_attrs = data;
812 819
813 820 (void) memcpy(lifrp->lifr_nd.lnr_hdw_addr, nd_attrs->lnr_hdw_addr,
814 821 ND_MAX_HDW_LEN);
815 822 lifrp->lifr_nd.lnr_hdw_len = nd_attrs->lnr_hdw_len;
816 823 lifrp->lifr_nd.lnr_flags = nd_attrs->lnr_flags;
817 824
818 825 lifrp->lifr_nd.lnr_state_create = nd_attrs->lnr_state_create;
819 826 lifrp->lifr_nd.lnr_state_same_lla = nd_attrs->lnr_state_same_lla;
820 827 lifrp->lifr_nd.lnr_state_diff_lla = nd_attrs->lnr_state_diff_lla;
821 828
822 829 if (ioctl(fd, SIOCLIFSETND, lifrp) < 0) {
823 830 ndp_lifr2ip(lifrp, ipaddr, sizeof (ipaddr));
824 831 if (errno == EPERM) {
825 832 warnx("Permission denied, "
826 833 "could not set entry for %s", ipaddr);
827 834 return (-1);
828 835 } else {
829 836 warnx("Failed to set mapping for %s: %s",
830 837 ipaddr, strerror(errno));
831 838 return (-1);
832 839 }
833 840 }
834 841
835 842 return (0);
836 843 }
837 844
838 845 /*
839 846 * Given a host identifier, a link-layer address and possible options,
840 847 * add/update the NDP mappings.
841 848 */
842 849 static int
843 850 ndp_set_nce(char *host, char *lladdr, char *opts[], int optlen)
844 851 {
845 852 lif_nd_req_t nd_attrs;
846 853 uchar_t *ea;
847 854 char *opt;
848 855 int i;
849 856 boolean_t temp = B_FALSE;
850 857 boolean_t any = B_FALSE;
851 858 boolean_t router = B_FALSE;
852 859
853 860 bzero(&nd_attrs, sizeof (lif_nd_req_t));
854 861
855 862 ea = _link_aton(lladdr, &nd_attrs.lnr_hdw_len);
856 863
857 864 if (ea == NULL) {
858 865 warnx("Unable to parse link-layer address \"%s\"", lladdr);
859 866 return (-1);
860 867 }
861 868
862 869 if (nd_attrs.lnr_hdw_len > sizeof (nd_attrs.lnr_hdw_addr)) {
863 870 warnx("The size of the link-layer address is "
864 871 "too large to set\n");
865 872 free(ea);
866 873 return (-1);
867 874 }
868 875
869 876 (void) memcpy(nd_attrs.lnr_hdw_addr, ea, nd_attrs.lnr_hdw_len);
870 877
871 878 free(ea);
872 879
873 880 nd_attrs.lnr_state_create = ND_REACHABLE;
874 881 nd_attrs.lnr_state_same_lla = ND_UNCHANGED;
875 882 nd_attrs.lnr_state_diff_lla = ND_STALE;
876 883
877 884 for (i = 0; i < optlen; i++) {
878 885 opt = opts[i];
879 886 if (strcmp(opt, "temp") == 0) {
880 887 temp = B_TRUE;
881 888 } else if (strcmp(opt, "any") == 0) {
882 889 any = B_TRUE;
883 890 } else if (strcmp(opt, "router") == 0) {
884 891 router = B_TRUE;
885 892 } else if (strcmp(opt, "proxy") == 0) {
886 893 warnx("NDP proxying is currently not supported");
887 894 return (-1);
888 895 } else {
889 896 warnx("Unrecognized option \"%s\"", opt);
890 897 return (-1);
891 898 }
892 899 }
893 900
894 901 if (!temp) {
895 902 nd_attrs.lnr_flags |= NDF_STATIC;
896 903 }
897 904
898 905 if (any) {
899 906 nd_attrs.lnr_flags |= NDF_ANYCAST_ON;
900 907 } else {
901 908 nd_attrs.lnr_flags |= NDF_ANYCAST_OFF;
902 909 }
903 910
904 911 if (router) {
905 912 nd_attrs.lnr_flags |= NDF_ISROUTER_OFF;
906 913 } else {
907 914 nd_attrs.lnr_flags |= NDF_ISROUTER_OFF;
908 915 }
909 916
910 917 return (ndp_host_enumerate(host, ndp_set, &nd_attrs));
911 918 }
912 919
913 920 /*
914 921 * Read in a file and set the mappings from each line.
915 922 */
916 923 static int
917 924 ndp_set_file(char *filename)
918 925 {
919 926 char *line = NULL, *lasts = NULL, *curr;
920 927 char *host, *lladdr;
921 928 char *opts[MAX_OPTS];
922 929 int optlen = 0, lineno = 0;
923 930 size_t cap = 0;
924 931 boolean_t failed_line = B_FALSE;
925 932 FILE *stream = fopen(filename, "r");
926 933
927 934 if (stream == NULL) {
928 935 ndp_fatal("Error while opening file %s: %s",
929 936 filename, strerror(errno));
930 937 }
931 938
932 939 errno = 0;
933 940 while (getline(&line, &cap, stream) != -1) {
934 941 lineno++;
935 942
936 943 if (line[0] == '#')
937 944 continue;
938 945
939 946 host = strtok_r(line, WORDSEPS, &lasts);
940 947 if (host == NULL) {
941 948 warnx("Line %d incomplete, skipping: "
942 949 "missing host identifier", lineno);
943 950 failed_line = B_TRUE;
944 951 continue;
945 952 }
946 953
947 954 lladdr = strtok_r(NULL, WORDSEPS, &lasts);
948 955 if (lladdr == NULL) {
949 956 warnx("Line %d incomplete, skipping: "
950 957 "missing link-layer address", lineno);
951 958 failed_line = B_TRUE;
952 959 continue;
953 960 }
954 961
955 962 for (optlen = 0; optlen < MAX_OPTS; optlen++) {
956 963 curr = strtok_r(NULL, WORDSEPS, &lasts);
957 964 if (curr == NULL)
958 965 break;
959 966 opts[optlen] = curr;
960 967 }
961 968
962 969 if (ndp_set_nce(host, lladdr, opts, optlen) != 0) {
963 970 failed_line = B_TRUE;
964 971 continue;
965 972 }
966 973 }
967 974
968 975 free(line);
969 976
970 977 if (errno != 0 || ferror(stream)) {
971 978 ndp_fatal("Error while reading from file %s: %s", filename,
972 979 strerror(errno));
973 980 }
974 981
975 982 if (fclose(stream) != 0) {
976 983 ndp_fatal("Error close file %s: %s", filename, strerror(errno));
977 984 }
978 985
979 986 return (failed_line ? -1 : 0);
980 987 }
981 988
982 989 int
983 990 main(int argc, char *argv[])
984 991 {
985 992 char *flagarg = NULL, *lladdr = NULL;
986 993 char **opts;
987 994 char *endptr;
988 995 int c, argsleft, optlen = 0, err = 0;
989 996 long long period;
990 997 enum ndp_action action = NDP_A_DEFAULT;
991 998
992 999 setprogname(basename(argv[0]));
993 1000
994 1001 if (argc < 2) {
995 1002 ndp_usage("No arguments given.");
996 1003 }
997 1004
998 1005 while ((c = getopt(argc, argv, ":naA:d:f:i:s:")) != -1) {
999 1006 switch (c) {
1000 1007 case 'n':
1001 1008 ndp_noresolve = B_TRUE;
1002 1009 break;
1003 1010 case 'i':
1004 1011 ndp_iface = optarg;
1005 1012 break;
1006 1013 case 's':
1007 1014 if (action != NDP_A_DEFAULT)
1008 1015 ndp_badflag(action);
1009 1016 action = NDP_A_SET_NCE;
1010 1017 flagarg = optarg;
1011 1018
1012 1019 if ((argc - optind) < 1) {
1013 1020 ndp_usage("Missing link-layer address after "
1014 1021 "the node address, \"%s\"", flagarg);
1015 1022 }
1016 1023 lladdr = argv[optind++];
1017 1024
1018 1025 /*
1019 1026 * Grab any following keywords up to the next flag
1020 1027 */
1021 1028 opts = argv + optind;
1022 1029 while ((argc - optind) > 0) {
1023 1030 if (argv[optind][0] == '-')
1024 1031 ndp_usage("Encountered \"%s\" after "
1025 1032 "flag parsing is done",
1026 1033 argv[optind]);
1027 1034 optind++;
1028 1035 optlen++;
1029 1036 }
1030 1037 break;
1031 1038 case 'a':
1032 1039 if (action != NDP_A_DEFAULT)
1033 1040 ndp_badflag(action);
1034 1041 action = NDP_A_GET_ALL;
1035 1042 break;
1036 1043 case 'A':
1037 1044 if (action != NDP_A_DEFAULT)
1038 1045 ndp_badflag(action);
1039 1046 action = NDP_A_GET_FOREVER;
1040 1047 flagarg = optarg;
1041 1048 break;
1042 1049 case 'd':
1043 1050 if (action != NDP_A_DEFAULT)
1044 1051 ndp_badflag(action);
1045 1052 action = NDP_A_DELETE;
1046 1053 flagarg = optarg;
1047 1054 break;
1048 1055 case 'f':
1049 1056 if (action != NDP_A_DEFAULT)
1050 1057 ndp_badflag(action);
1051 1058 action = NDP_A_SET_FILE;
1052 1059 flagarg = optarg;
1053 1060 break;
1054 1061 case ':':
1055 1062 ndp_missingarg(optopt);
1056 1063 break;
1057 1064 case '?':
1058 1065 ndp_usage("Unrecognized flag \"-%c\"", optopt);
1059 1066 default:
1060 1067 ndp_usage(NULL);
1061 1068 }
1062 1069 }
1063 1070
1064 1071 argsleft = argc - optind;
1065 1072 ndp_pid = getpid();
1066 1073
1067 1074 if (action != NDP_A_DEFAULT && argsleft != 0) {
1068 1075 ndp_usage("Extra arguments leftover after parsing flags");
1069 1076 }
1070 1077
1071 1078 switch (action) {
1072 1079 case NDP_A_DEFAULT:
1073 1080 case NDP_A_GET:
1074 1081 if (argsleft != 1) {
1075 1082 ndp_usage("Multiple arguments given without any flags");
1076 1083 }
1077 1084 err = ndp_host_enumerate(argv[optind], ndp_get, NULL);
1078 1085 break;
1079 1086 case NDP_A_GET_ALL:
1080 1087 ndp_get_all();
1081 1088 /*NOTREACHED*/
1082 1089 break;
1083 1090 case NDP_A_GET_FOREVER:
1084 1091 errno = 0;
1085 1092 period = strtoll(flagarg, &endptr, 10);
1086 1093 if ((period == 0 && errno != 0) ||
1087 1094 (endptr[0] != '\0') ||
1088 1095 (period < 0)) {
1089 1096 ndp_usage("Given period should be a positive integer,"
1090 1097 " not \"%s\"", flagarg);
1091 1098 }
1092 1099 if (period > 86400) {
1093 1100 ndp_usage("Given period should be shorter than a day;"
1094 1101 " given \"%s\" seconds", flagarg);
1095 1102 }
1096 1103 ndp_run_periodically(period, ndp_get_all);
1097 1104 /*NOTREACHED*/
1098 1105 break;
1099 1106 case NDP_A_DELETE:
1100 1107 err = ndp_host_enumerate(flagarg, ndp_delete, NULL);
1101 1108 break;
1102 1109 case NDP_A_SET_NCE:
1103 1110 err = ndp_set_nce(flagarg, lladdr, opts, optlen);
1104 1111 break;
1105 1112 case NDP_A_SET_FILE:
1106 1113 err = ndp_set_file(flagarg);
1107 1114 break;
1108 1115 }
1109 1116
1110 1117 return (err == 0 ? 0 : 1);
1111 1118 }
|
↓ open down ↓ |
332 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX