1/* 2 * 3 * Modified for AF_INET6 by Pedro Roque 4 * 5 * <roque@di.fc.ul.pt> 6 * 7 * Original copyright notice included bellow 8 */ 9 10/* 11 * Copyright (c) 1989 The Regents of the University of California. 12 * All rights reserved. 13 * 14 * This code is derived from software contributed to Berkeley by 15 * Mike Muuss. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the University of 28 * California, Berkeley and its contributors. 29 * 4. Neither the name of the University nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 */ 45 46#ifndef lint 47char copyright[] = 48"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 49 All rights reserved.\n"; 50#endif /* not lint */ 51 52/* 53 * P I N G . C 54 * 55 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, 56 * measure round-trip-delays and packet loss across network paths. 57 * 58 * Author - 59 * Mike Muuss 60 * U. S. Army Ballistic Research Laboratory 61 * December, 1983 62 * 63 * Status - 64 * Public Domain. Distribution Unlimited. 65 * Bugs - 66 * More statistics could always be gathered. 67 * This program has to run SUID to ROOT to access the ICMP socket. 68 */ 69#include "ping_common.h" 70 71#include <linux/filter.h> 72#include <netinet/ip6.h> 73#include <netinet/icmp6.h> 74#include <resolv.h> 75#ifndef WITHOUT_IFADDRS 76#include <ifaddrs.h> 77#endif 78 79#ifdef USE_IDN 80#include <stringprep.h> 81#endif 82 83#include "ping6_niquery.h" 84#include "in6_flowlabel.h" 85 86#ifndef SOL_IPV6 87#define SOL_IPV6 IPPROTO_IPV6 88#endif 89 90#ifndef SOL_ICMPV6 91#define SOL_ICMPV6 IPPROTO_ICMPV6 92#endif 93 94/* RFC3542 */ 95#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE 96#define ICMP6_DST_UNREACH_BEYONDSCOPE ICMP6_DST_UNREACH_NOTNEIGHBOR 97#endif 98 99#if defined(ENABLE_PING6_RTHDR) && !defined(ENABLE_PING6_RTHDR_RFC3542) 100#ifndef IPV6_SRCRT_TYPE_0 101#define IPV6_SRCRT_TYPE_0 0 102#endif 103#endif 104 105#ifndef MLD_LISTENER_QUERY 106#define MLD_LISTENER_QUERY 130 107#define MLD_LISTENER_REPORT 131 108#define MLD_LISTENER_REDUCTION 132 109#endif 110 111#define BIT_CLEAR(nr, addr) do { ((__u32 *)(addr))[(nr) >> 5] &= ~(1U << ((nr) & 31)); } while(0) 112#define BIT_SET(nr, addr) do { ((__u32 *)(addr))[(nr) >> 5] |= (1U << ((nr) & 31)); } while(0) 113#define BIT_TEST(nr, addr) do { (__u32 *)(addr))[(nr) >> 5] & (1U << ((nr) & 31)); } while(0) 114 115#ifndef ICMP6_FILTER_WILLPASS 116#define ICMP6_FILTER_WILLPASS(type, filterp) \ 117 (BIT_TEST((type), filterp) == 0) 118 119#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ 120 BIT_TEST((type), filterp) 121 122#define ICMP6_FILTER_SETPASS(type, filterp) \ 123 BIT_CLEAR((type), filterp) 124 125#define ICMP6_FILTER_SETBLOCK(type, filterp) \ 126 BIT_SET((type), filterp) 127 128#define ICMP6_FILTER_SETPASSALL(filterp) \ 129 memset(filterp, 0, sizeof(struct icmp6_filter)); 130 131#define ICMP6_FILTER_SETBLOCKALL(filterp) \ 132 memset(filterp, 0xFF, sizeof(struct icmp6_filter)); 133#endif 134 135#define MAXPACKET 128000 /* max packet size */ 136 137#ifdef SO_TIMESTAMP 138#define HAVE_SIN6_SCOPEID 1 139#endif 140 141#ifndef SCOPE_DELIMITER 142# define SCOPE_DELIMITER '%' 143#endif 144 145__u32 flowlabel; 146__u32 tclass; 147#ifdef ENABLE_PING6_RTHDR 148struct cmsghdr *srcrt; 149#endif 150 151struct sockaddr_in6 whereto; /* who to ping */ 152u_char outpack[MAXPACKET]; 153int maxpacket = sizeof(outpack); 154 155static unsigned char cmsgbuf[4096]; 156static int cmsglen = 0; 157 158static char * pr_addr(struct in6_addr *addr); 159static char * pr_addr_n(struct in6_addr *addr); 160static int pr_icmph(__u8 type, __u8 code, __u32 info); 161static void usage(void) __attribute((noreturn)); 162 163struct sockaddr_in6 source; 164char *device; 165int pmtudisc=-1; 166 167static int icmp_sock; 168 169#ifdef USE_GNUTLS 170# include <gnutls/openssl.h> 171#else 172# include <openssl/md5.h> 173#endif 174 175/* Node Information query */ 176int ni_query = -1; 177int ni_flag = 0; 178void *ni_subject = NULL; 179int ni_subject_len = 0; 180int ni_subject_type = -1; 181char *ni_group; 182 183static inline int ntohsp(__u16 *p) 184{ 185 __u16 v; 186 memcpy(&v, p, sizeof(v)); 187 return ntohs(v); 188} 189 190#if defined(ENABLE_PING6_RTHDR) && !defined(ENABLE_PING6_RTHDR_RFC3542) 191size_t inet6_srcrt_space(int type, int segments) 192{ 193 if (type != 0 || segments > 24) 194 return 0; 195 196 return (sizeof(struct cmsghdr) + sizeof(struct ip6_rthdr0) + 197 segments * sizeof(struct in6_addr)); 198} 199 200extern struct cmsghdr * inet6_srcrt_init(void *bp, int type) 201{ 202 struct cmsghdr *cmsg; 203 204 if (type) 205 return NULL; 206 207 memset(bp, 0, sizeof(struct cmsghdr) + sizeof(struct ip6_rthdr0)); 208 cmsg = (struct cmsghdr *) bp; 209 210 cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct ip6_rthdr0); 211 cmsg->cmsg_level = SOL_IPV6; 212 cmsg->cmsg_type = IPV6_RTHDR; 213 214 return cmsg; 215} 216 217int inet6_srcrt_add(struct cmsghdr *cmsg, const struct in6_addr *addr) 218{ 219 struct ip6_rthdr0 *hdr; 220 221 hdr = (struct ip6_rthdr0 *) CMSG_DATA(cmsg); 222 223 cmsg->cmsg_len += sizeof(struct in6_addr); 224 hdr->ip6r0_len += sizeof(struct in6_addr) / 8; 225 226 memcpy(&hdr->ip6r0_addr[hdr->ip6r0_segleft++], addr, 227 sizeof(struct in6_addr)); 228 229 return 0; 230} 231#endif 232 233unsigned int if_name2index(const char *ifname) 234{ 235 unsigned int i = if_nametoindex(ifname); 236 if (!i) { 237 fprintf(stderr, "ping: unknown iface %s\n", ifname); 238 exit(2); 239 } 240 return i; 241} 242 243struct niquery_option { 244 char *name; 245 int namelen; 246 int has_arg; 247 int data; 248 int (*handler)(int index, const char *arg); 249}; 250 251#define NIQUERY_OPTION(_name, _has_arg, _data, _handler) \ 252 { \ 253 .name = _name, \ 254 .namelen = sizeof(_name) - 1, \ 255 .has_arg = _has_arg, \ 256 .data = _data, \ 257 .handler = _handler \ 258 } 259 260static int niquery_option_name_handler(int index, const char *arg); 261static int niquery_option_ipv6_handler(int index, const char *arg); 262static int niquery_option_ipv6_flag_handler(int index, const char *arg); 263static int niquery_option_ipv4_handler(int index, const char *arg); 264static int niquery_option_ipv4_flag_handler(int index, const char *arg); 265static int niquery_option_subject_addr_handler(int index, const char *arg); 266static int niquery_option_subject_name_handler(int index, const char *arg); 267static int niquery_option_help_handler(int index, const char *arg); 268 269struct niquery_option niquery_options[] = { 270 NIQUERY_OPTION("name", 0, 0, niquery_option_name_handler), 271 NIQUERY_OPTION("fqdn", 0, 0, niquery_option_name_handler), 272 NIQUERY_OPTION("ipv6", 0, 0, niquery_option_ipv6_handler), 273 NIQUERY_OPTION("ipv6-all", 0, NI_IPV6ADDR_F_ALL, niquery_option_ipv6_flag_handler), 274 NIQUERY_OPTION("ipv6-compatible", 0, NI_IPV6ADDR_F_COMPAT, niquery_option_ipv6_flag_handler), 275 NIQUERY_OPTION("ipv6-linklocal", 0, NI_IPV6ADDR_F_LINKLOCAL, niquery_option_ipv6_flag_handler), 276 NIQUERY_OPTION("ipv6-sitelocal", 0, NI_IPV6ADDR_F_SITELOCAL, niquery_option_ipv6_flag_handler), 277 NIQUERY_OPTION("ipv6-global", 0, NI_IPV6ADDR_F_GLOBAL, niquery_option_ipv6_flag_handler), 278 NIQUERY_OPTION("ipv4", 0, 0, niquery_option_ipv4_handler), 279 NIQUERY_OPTION("ipv4-all", 0, NI_IPV4ADDR_F_ALL, niquery_option_ipv4_flag_handler), 280 NIQUERY_OPTION("subject-ipv6", 1, NI_SUBJ_IPV6, niquery_option_subject_addr_handler), 281 NIQUERY_OPTION("subject-ipv4", 1, NI_SUBJ_IPV4, niquery_option_subject_addr_handler), 282 NIQUERY_OPTION("subject-name", 1, 0, niquery_option_subject_name_handler), 283 NIQUERY_OPTION("subject-fqdn", 1, -1, niquery_option_subject_name_handler), 284 NIQUERY_OPTION("help", 0, 0, niquery_option_help_handler), 285 {}, 286}; 287 288static inline int niquery_is_enabled(void) 289{ 290 return ni_query >= 0; 291} 292 293#if PING6_NONCE_MEMORY 294__u8 *ni_nonce_ptr; 295#else 296struct { 297 struct timeval tv; 298 pid_t pid; 299} ni_nonce_secret; 300#endif 301 302static void niquery_init_nonce(void) 303{ 304#if PING6_NONCE_MEMORY 305 struct timeval tv; 306 unsigned long seed; 307 308 seed = (unsigned long)getpid(); 309 if (!gettimeofday(&tv, NULL)) 310 seed ^= tv.tv_usec; 311 srand(seed); 312 313 ni_nonce_ptr = calloc(NI_NONCE_SIZE, MAX_DUP_CHK); 314 if (!ni_nonce_ptr) { 315 perror("ping6: calloc"); 316 exit(2); 317 } 318 319 ni_nonce_ptr[0] = ~0; 320#else 321 gettimeofday(&ni_nonce_secret.tv, NULL); 322 ni_nonce_secret.pid = getpid(); 323#endif 324} 325 326#if !PING6_NONCE_MEMORY 327static int niquery_nonce(__u8 *nonce, int fill) 328{ 329 static __u8 digest[MD5_DIGEST_LENGTH]; 330 static int seq = -1; 331 332 if (fill || seq != *(__u16 *)nonce || seq < 0) { 333 MD5_CTX ctxt; 334 335 MD5_Init(&ctxt); 336 MD5_Update(&ctxt, &ni_nonce_secret, sizeof(ni_nonce_secret)); 337 MD5_Update(&ctxt, nonce, sizeof(__u16)); 338 MD5_Final(digest, &ctxt); 339 340 seq = *(__u16 *)nonce; 341 } 342 343 if (fill) { 344 memcpy(nonce + sizeof(__u16), digest, NI_NONCE_SIZE - sizeof(__u16)); 345 return 0; 346 } else { 347 if (memcmp(nonce + sizeof(__u16), digest, NI_NONCE_SIZE - sizeof(__u16))) 348 return -1; 349 return ntohsp((__u16 *)nonce); 350 } 351} 352#endif 353 354static inline void niquery_fill_nonce(__u16 seq, __u8 *nonce) 355{ 356 __u16 v = htons(seq); 357#if PING6_NONCE_MEMORY 358 int i; 359 360 memcpy(&ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], &v, sizeof(v)); 361 362 for (i = sizeof(v); i < NI_NONCE_SIZE; i++) 363 ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK) + i] = 0x100 * (rand() / (RAND_MAX + 1.0)); 364 365 memcpy(nonce, &ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], NI_NONCE_SIZE); 366#else 367 memcpy(nonce, &v, sizeof(v)); 368 niquery_nonce(nonce, 1); 369#endif 370} 371 372static inline int niquery_check_nonce(__u8 *nonce) 373{ 374#if PING6_NONCE_MEMORY 375 __u16 seq = ntohsp((__u16 *)nonce); 376 if (memcmp(nonce, &ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], NI_NONCE_SIZE)) 377 return -1; 378 return seq; 379#else 380 return niquery_nonce(nonce, 0); 381#endif 382} 383 384static int niquery_set_qtype(int type) 385{ 386 if (niquery_is_enabled() && ni_query != type) { 387 printf("Qtype conflict\n"); 388 return -1; 389 } 390 ni_query = type; 391 return 0; 392} 393 394static int niquery_option_name_handler(int index, const char *arg) 395{ 396 if (niquery_set_qtype(NI_QTYPE_NAME) < 0) 397 return -1; 398 return 0; 399} 400 401static int niquery_option_ipv6_handler(int index, const char *arg) 402{ 403 if (niquery_set_qtype(NI_QTYPE_IPV6ADDR) < 0) 404 return -1; 405 return 0; 406} 407 408static int niquery_option_ipv6_flag_handler(int index, const char *arg) 409{ 410 if (niquery_set_qtype(NI_QTYPE_IPV6ADDR) < 0) 411 return -1; 412 ni_flag |= niquery_options[index].data; 413 return 0; 414} 415 416static int niquery_option_ipv4_handler(int index, const char *arg) 417{ 418 if (niquery_set_qtype(NI_QTYPE_IPV4ADDR) < 0) 419 return -1; 420 return 0; 421} 422 423static int niquery_option_ipv4_flag_handler(int index, const char *arg) 424{ 425 if (niquery_set_qtype(NI_QTYPE_IPV4ADDR) < 0) 426 return -1; 427 ni_flag |= niquery_options[index].data; 428 return 0; 429} 430 431static inline int niquery_is_subject_valid(void) 432{ 433 return ni_subject_type >= 0 && ni_subject; 434} 435 436static int niquery_set_subject_type(int type) 437{ 438 if (niquery_is_subject_valid() && ni_subject_type != type) { 439 printf("Subject type conflict\n"); 440 return -1; 441 } 442 ni_subject_type = type; 443 return 0; 444} 445 446#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) 447#define OFFSET_OF(type,elem) ((size_t)&((type *)0)->elem) 448 449static int niquery_option_subject_addr_handler(int index, const char *arg) 450{ 451 struct addrinfo hints, *ai0, *ai; 452 int offset; 453 int gai; 454 455 if (niquery_set_subject_type(niquery_options[index].data) < 0) 456 return -1; 457 458 ni_subject_type = niquery_options[index].data; 459 460 memset(&hints, 0, sizeof(hints)); 461 462 switch (niquery_options[index].data) { 463 case NI_SUBJ_IPV6: 464 ni_subject_len = sizeof(struct in6_addr); 465 offset = OFFSET_OF(struct sockaddr_in6, sin6_addr); 466 hints.ai_family = AF_INET6; 467 break; 468 case NI_SUBJ_IPV4: 469 ni_subject_len = sizeof(struct in_addr); 470 offset = OFFSET_OF(struct sockaddr_in, sin_addr); 471 hints.ai_family = AF_INET; 472 break; 473 default: 474 /* should not happen. */ 475 offset = -1; 476 } 477 478 hints.ai_socktype = SOCK_DGRAM; 479#ifdef USE_IDN 480 hints.ai_flags = AI_IDN; 481#endif 482 483 gai = getaddrinfo(arg, 0, &hints, &ai0); 484 if (gai) { 485 fprintf(stderr, "Unknown host: %s\n", arg); 486 return -1; 487 } 488 489 for (ai = ai0; ai; ai = ai->ai_next) { 490 void *p = malloc(ni_subject_len); 491 if (!p) 492 continue; 493 memcpy(p, (__u8 *)ai->ai_addr + offset, ni_subject_len); 494 free(ni_subject); 495 ni_subject = p; 496 break; 497 } 498 freeaddrinfo(ai0); 499 500 return 0; 501} 502 503static int niquery_option_subject_name_handler(int index, const char *arg) 504{ 505 static char nigroup_buf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ]; 506 unsigned char *dnptrs[2], **dpp, **lastdnptr; 507 int n; 508 int i; 509 char *name, *p; 510 char *canonname = NULL, *idn = NULL; 511 unsigned char *buf = NULL; 512 size_t namelen; 513 size_t buflen; 514 int dots, fqdn = niquery_options[index].data; 515 MD5_CTX ctxt; 516 __u8 digest[MD5_DIGEST_LENGTH]; 517#ifdef USE_IDN 518 int rc; 519#endif 520 521 if (niquery_set_subject_type(NI_SUBJ_NAME) < 0) 522 return -1; 523 524#ifdef USE_IDN 525 name = stringprep_locale_to_utf8(arg); 526 if (!name) { 527 fprintf(stderr, "ping6: IDN support failed.\n"); 528 exit(2); 529 } 530#else 531 name = strdup(arg); 532 if (!name) 533 goto oomexit; 534#endif 535 536 p = strchr(name, SCOPE_DELIMITER); 537 if (p) { 538 *p = '\0'; 539 if (strlen(p + 1) >= IFNAMSIZ) { 540 fprintf(stderr, "ping6: too long scope name.\n"); 541 exit(1); 542 } 543 } 544 545#ifdef USE_IDN 546 rc = idna_to_ascii_8z(name, &idn, 0); 547 if (rc) { 548 fprintf(stderr, "ping6: IDN encoding error: %s\n", 549 idna_strerror(rc)); 550 exit(2); 551 } 552#else 553 idn = strdup(name); 554 if (!idn) 555 goto oomexit; 556#endif 557 558 namelen = strlen(idn); 559 canonname = malloc(namelen + 1); 560 if (!canonname) 561 goto oomexit; 562 563 dots = 0; 564 for (i = 0; i < namelen + 1; i++) { 565 canonname[i] = isupper(idn[i]) ? tolower(idn[i]) : idn[i]; 566 if (idn[i] == '.') 567 dots++; 568 } 569 570 if (fqdn == 0) { 571 /* guess if hostname is FQDN */ 572 fqdn = dots ? 1 : -1; 573 } 574 575 buflen = namelen + 3 + 1; /* dn_comp() requrires strlen() + 3, 576 plus non-fqdn indicator. */ 577 buf = malloc(buflen); 578 if (!buf) { 579 fprintf(stderr, "ping6: out of memory.\n"); 580 goto errexit; 581 } 582 583 dpp = dnptrs; 584 lastdnptr = &dnptrs[ARRAY_SIZE(dnptrs)]; 585 586 *dpp++ = (unsigned char *)buf; 587 *dpp++ = NULL; 588 589 n = dn_comp(canonname, (unsigned char *)buf, buflen, dnptrs, lastdnptr); 590 if (n < 0) { 591 fprintf(stderr, "ping6: Inappropriate subject name: %s\n", canonname); 592 goto errexit; 593 } else if (n >= buflen) { 594 fprintf(stderr, "ping6: dn_comp() returned too long result.\n"); 595 goto errexit; 596 } 597 598 MD5_Init(&ctxt); 599 MD5_Update(&ctxt, buf, buf[0]); 600 MD5_Final(digest, &ctxt); 601 602 sprintf(nigroup_buf, "ff02::2:%02x%02x:%02x%02x%s%s", 603 digest[0], digest[1], digest[2], digest[3], 604 p ? "%" : "", 605 p ? p + 1 : ""); 606 607 if (fqdn < 0) 608 buf[n] = 0; 609 610 free(ni_subject); 611 612 ni_group = nigroup_buf; 613 ni_subject = buf; 614 ni_subject_len = n + (fqdn < 0); 615 ni_group = nigroup_buf; 616 617 free(canonname); 618 free(idn); 619 free(name); 620 621 return 0; 622oomexit: 623 fprintf(stderr, "ping6: out of memory.\n"); 624errexit: 625 free(buf); 626 free(canonname); 627 free(idn); 628 free(name); 629 exit(1); 630} 631 632int niquery_option_help_handler(int index, const char *arg) 633{ 634 fprintf(stderr, "ping6 -N suboptions\n" 635 "\tHelp:\n" 636 "\t\thelp\n" 637 "\tQuery:\n" 638 "\t\tname,\n" 639 "\t\tipv6,ipv6-all,ipv6-compatible,ipv6-linklocal,ipv6-sitelocal,ipv6-global,\n" 640 "\t\tipv4,ipv4-all,\n" 641 "\tSubject:\n" 642 "\t\tsubject-ipv6=addr,subject-ipv4=addr,subject-name=name,subject-fqdn=name,\n" 643 ); 644 exit(2); 645} 646 647int niquery_option_handler(const char *opt_arg) 648{ 649 struct niquery_option *p; 650 int i; 651 int ret = -1; 652 for (i = 0, p = niquery_options; p->name; i++, p++) { 653 if (strncmp(p->name, opt_arg, p->namelen)) 654 continue; 655 if (!p->has_arg) { 656 if (opt_arg[p->namelen] == '\0') { 657 ret = p->handler(i, NULL); 658 if (ret >= 0) 659 break; 660 } 661 } else { 662 if (opt_arg[p->namelen] == '=') { 663 ret = p->handler(i, &opt_arg[p->namelen] + 1); 664 if (ret >= 0) 665 break; 666 } 667 } 668 } 669 if (!p->name) 670 ret = niquery_option_help_handler(0, NULL); 671 return ret; 672} 673 674static int hextoui(const char *str) 675{ 676 unsigned long val; 677 char *ep; 678 679 errno = 0; 680 val = strtoul(str, &ep, 16); 681 if (*ep) { 682 if (!errno) 683 errno = EINVAL; 684 return -1; 685 } 686 687 if (val > UINT_MAX) { 688 errno = ERANGE; 689 return UINT_MAX; 690 } 691 692 return val; 693} 694 695int main(int argc, char *argv[]) 696{ 697 int ch, hold, packlen; 698 u_char *packet; 699 char *target; 700 struct addrinfo hints, *ai; 701 int gai; 702 struct sockaddr_in6 firsthop; 703 int socket_errno = 0; 704 struct icmp6_filter filter; 705 int err; 706#ifdef __linux__ 707 int csum_offset, sz_opt; 708#endif 709 static uint32_t scope_id = 0; 710 711#ifdef ANDROID 712 android_check_security(); 713#endif 714 715 limit_capabilities(); 716 717#ifdef USE_IDN 718 setlocale(LC_ALL, ""); 719#endif 720 721 icmp_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 722 if (icmp_sock < 0) { 723 enable_capability_raw(); 724 icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 725 socket_errno = errno; 726 disable_capability_raw(); 727 using_ping_socket = 0; 728 } 729 730 source.sin6_family = AF_INET6; 731 memset(&firsthop, 0, sizeof(firsthop)); 732 firsthop.sin6_family = AF_INET6; 733 734 preload = 1; 735 while ((ch = getopt(argc, argv, COMMON_OPTSTR "F:N:")) != EOF) { 736 switch(ch) { 737 case 'F': 738 flowlabel = hextoui(optarg); 739 if (errno || (flowlabel & ~IPV6_FLOWINFO_FLOWLABEL)) { 740 fprintf(stderr, "ping: Invalid flowinfo %s\n", optarg); 741 exit(2); 742 } 743 options |= F_FLOWINFO; 744 break; 745 case 'Q': 746 tclass = hextoui(optarg); 747 if (errno || (tclass & ~0xff)) { 748 fprintf(stderr, "ping: Invalid tclass %s\n", optarg); 749 exit(2); 750 } 751 options |= F_TCLASS; 752 break; 753 case 'I': 754 if (strchr(optarg, ':')) { 755 char *p, *addr = strdup(optarg); 756 757 if (!addr) { 758 fprintf(stderr, "ping: out of memory\n"); 759 exit(2); 760 } 761 762 p = strchr(addr, SCOPE_DELIMITER); 763 if (p) { 764 *p = '\0'; 765 device = optarg + (p - addr) + 1; 766 } 767 768 if (inet_pton(AF_INET6, addr, (char*)&source.sin6_addr) <= 0) { 769 fprintf(stderr, "ping: invalid source address %s\n", optarg); 770 exit(2); 771 } 772 773 options |= F_STRICTSOURCE; 774 775 free(addr); 776 } else { 777 device = optarg; 778 } 779 break; 780 case 'M': 781 if (strcmp(optarg, "do") == 0) 782 pmtudisc = IPV6_PMTUDISC_DO; 783 else if (strcmp(optarg, "dont") == 0) 784 pmtudisc = IPV6_PMTUDISC_DONT; 785 else if (strcmp(optarg, "want") == 0) 786 pmtudisc = IPV6_PMTUDISC_WANT; 787 else { 788 fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n"); 789 exit(2); 790 } 791 break; 792 case 'V': 793 printf("ping6 utility, iputils-%s\n", SNAPSHOT); 794 exit(0); 795 case 'N': 796 if (using_ping_socket) { 797 fprintf(stderr, "ping: -N requires raw socket permissions\n"); 798 exit(2); 799 } 800 if (niquery_option_handler(optarg) < 0) { 801 usage(); 802 break; 803 } 804 break; 805 COMMON_OPTIONS 806 common_options(ch); 807 break; 808 default: 809 usage(); 810 } 811 } 812 argc -= optind; 813 argv += optind; 814 815#ifdef ENABLE_PING6_RTHDR 816 while (argc > 1) { 817 struct in6_addr *addr; 818 819 if (srcrt == NULL) { 820 int space; 821 822 fprintf(stderr, "ping6: Warning: " 823 "Source routing is deprecated by RFC5095.\n"); 824 825#ifdef ENABLE_PING6_RTHDR_RFC3542 826 space = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); 827#else 828 space = inet6_srcrt_space(IPV6_SRCRT_TYPE_0, argc - 1); 829#endif 830 if (space == 0) { 831 fprintf(stderr, "srcrt_space failed\n"); 832 exit(2); 833 } 834#ifdef ENABLE_PING6_RTHDR_RFC3542 835 if (cmsglen + CMSG_SPACE(space) > sizeof(cmsgbuf)) { 836 fprintf(stderr, "no room for options\n"); 837 exit(2); 838 } 839#else 840 if (space + cmsglen > sizeof(cmsgbuf)) { 841 fprintf(stderr, "no room for options\n"); 842 exit(2); 843 } 844#endif 845 srcrt = (struct cmsghdr*)(cmsgbuf+cmsglen); 846#ifdef ENABLE_PING6_RTHDR_RFC3542 847 memset(srcrt, 0, CMSG_SPACE(0)); 848 srcrt->cmsg_len = CMSG_LEN(space); 849 srcrt->cmsg_level = IPPROTO_IPV6; 850 srcrt->cmsg_type = IPV6_RTHDR; 851 inet6_rth_init(CMSG_DATA(srcrt), space, IPV6_RTHDR_TYPE_0, argc - 1); 852 cmsglen += CMSG_SPACE(space); 853#else 854 cmsglen += CMSG_ALIGN(space); 855 inet6_srcrt_init(srcrt, IPV6_SRCRT_TYPE_0); 856#endif 857 } 858 859 target = *argv; 860 861 memset(&hints, 0, sizeof(hints)); 862 hints.ai_family = AF_INET6; 863#ifdef USE_IDN 864 hints.ai_flags = AI_IDN; 865#endif 866 gai = getaddrinfo(target, NULL, &hints, &ai); 867 if (gai) { 868 fprintf(stderr, "unknown host\n"); 869 exit(2); 870 } 871 addr = &((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr; 872#ifdef ENABLE_PING6_RTHDR_RFC3542 873 inet6_rth_add(CMSG_DATA(srcrt), addr); 874#else 875 inet6_srcrt_add(srcrt, addr); 876#endif 877 if (IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) { 878 memcpy(&firsthop.sin6_addr, addr, 16); 879#ifdef HAVE_SIN6_SCOPEID 880 firsthop.sin6_scope_id = ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_scope_id; 881 /* Verify scope_id is the same as previous nodes */ 882 if (firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) { 883 fprintf(stderr, "scope discrepancy among the nodes\n"); 884 exit(2); 885 } else if (!scope_id) { 886 scope_id = firsthop.sin6_scope_id; 887 } 888#endif 889 } 890 freeaddrinfo(ai); 891 892 argv++; 893 argc--; 894 } 895#endif 896 897 if (niquery_is_enabled()) { 898 niquery_init_nonce(); 899 900 if (!niquery_is_subject_valid()) { 901 ni_subject = &whereto.sin6_addr; 902 ni_subject_len = sizeof(whereto.sin6_addr); 903 ni_subject_type = NI_SUBJ_IPV6; 904 } 905 } 906 907 if (argc > 1) { 908#ifndef ENABLE_PING6_RTHDR 909 fprintf(stderr, "ping6: Source routing is deprecated by RFC5095.\n"); 910#endif 911 usage(); 912 } else if (argc == 1) { 913 target = *argv; 914 } else { 915 if (ni_query < 0 && ni_subject_type != NI_SUBJ_NAME) 916 usage(); 917 target = ni_group; 918 } 919 920 memset(&hints, 0, sizeof(hints)); 921 hints.ai_family = AF_INET6; 922#ifdef USE_IDN 923 hints.ai_flags = AI_IDN; 924#endif 925 gai = getaddrinfo(target, NULL, &hints, &ai); 926 if (gai) { 927 fprintf(stderr, "unknown host\n"); 928 exit(2); 929 } 930 931 memcpy(&whereto, ai->ai_addr, sizeof(whereto)); 932 whereto.sin6_port = htons(IPPROTO_ICMPV6); 933 934 if (memchr(target, ':', strlen(target))) 935 options |= F_NUMERIC; 936 937 freeaddrinfo(ai); 938 939 if (IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) { 940 memcpy(&firsthop.sin6_addr, &whereto.sin6_addr, 16); 941#ifdef HAVE_SIN6_SCOPEID 942 firsthop.sin6_scope_id = whereto.sin6_scope_id; 943 /* Verify scope_id is the same as intermediate nodes */ 944 if (firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) { 945 fprintf(stderr, "scope discrepancy among the nodes\n"); 946 exit(2); 947 } else if (!scope_id) { 948 scope_id = firsthop.sin6_scope_id; 949 } 950#endif 951 } 952 953 hostname = target; 954 955 if (IN6_IS_ADDR_UNSPECIFIED(&source.sin6_addr)) { 956 socklen_t alen; 957 int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); 958 959 if (probe_fd < 0) { 960 perror("socket"); 961 exit(2); 962 } 963 if (device) { 964#if defined(IPV6_RECVPKTINFO) || defined(HAVE_SIN6_SCOPEID) 965 unsigned int iface = if_name2index(device); 966#endif 967#ifdef IPV6_RECVPKTINFO 968 struct in6_pktinfo ipi; 969 970 memset(&ipi, 0, sizeof(ipi)); 971 ipi.ipi6_ifindex = iface; 972#endif 973 974#ifdef HAVE_SIN6_SCOPEID 975 if (IN6_IS_ADDR_LINKLOCAL(&firsthop.sin6_addr) || 976 IN6_IS_ADDR_MC_LINKLOCAL(&firsthop.sin6_addr)) 977 firsthop.sin6_scope_id = iface; 978#endif 979 enable_capability_raw(); 980 if ( 981#ifdef IPV6_RECVPKTINFO 982 setsockopt(probe_fd, IPPROTO_IPV6, IPV6_PKTINFO, &ipi, sizeof(ipi)) == -1 && 983#endif 984 setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) { 985 perror("setsockopt(SO_BINDTODEVICE)"); 986 exit(2); 987 } 988 disable_capability_raw(); 989 } 990 firsthop.sin6_port = htons(1025); 991 992 sock_setmark(probe_fd); 993 994 if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) { 995 perror("connect"); 996 exit(2); 997 } 998 alen = sizeof(source); 999 if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) { 1000 perror("getsockname"); 1001 exit(2); 1002 } 1003 source.sin6_port = 0; 1004 close(probe_fd); 1005 1006#ifndef WITHOUT_IFADDRS 1007 if (device) { 1008 struct ifaddrs *ifa0, *ifa; 1009 1010 if (getifaddrs(&ifa0)) { 1011 perror("getifaddrs"); 1012 exit(2); 1013 } 1014 1015 for (ifa = ifa0; ifa; ifa = ifa->ifa_next) { 1016 if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6) 1017 continue; 1018 if (!strncmp(ifa->ifa_name, device, sizeof(device) - 1) && 1019 IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, 1020 &source.sin6_addr)) 1021 break; 1022 } 1023 if (!ifa) 1024 fprintf(stderr, "ping6: Warning: source address might be selected on device other than %s.\n", device); 1025 1026 freeifaddrs(ifa0); 1027 } 1028#endif 1029 } 1030#ifdef HAVE_SIN6_SCOPEID 1031 else if (device && (IN6_IS_ADDR_LINKLOCAL(&source.sin6_addr) || 1032 IN6_IS_ADDR_MC_LINKLOCAL(&source.sin6_addr))) 1033 source.sin6_scope_id = if_name2index(device); 1034#endif 1035 1036 if (icmp_sock < 0) { 1037 errno = socket_errno; 1038 perror("ping: icmp open socket"); 1039 exit(2); 1040 } 1041 1042 if (device) { 1043 struct cmsghdr *cmsg; 1044 struct in6_pktinfo *ipi; 1045 1046 cmsg = (struct cmsghdr*)(cmsgbuf+cmsglen); 1047 cmsglen += CMSG_SPACE(sizeof(*ipi)); 1048 cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); 1049 cmsg->cmsg_level = SOL_IPV6; 1050 cmsg->cmsg_type = IPV6_PKTINFO; 1051 1052 ipi = (struct in6_pktinfo*)CMSG_DATA(cmsg); 1053 memset(ipi, 0, sizeof(*ipi)); 1054 ipi->ipi6_ifindex = if_name2index(device); 1055 } 1056 1057 if ((whereto.sin6_addr.s6_addr16[0]&htons(0xff00)) == htons (0xff00)) { 1058 if (uid) { 1059 if (interval < 1000) { 1060 fprintf(stderr, "ping: multicast ping with too short interval.\n"); 1061 exit(2); 1062 } 1063 if (pmtudisc >= 0 && pmtudisc != IPV6_PMTUDISC_DO) { 1064 fprintf(stderr, "ping: multicast ping does not fragment.\n"); 1065 exit(2); 1066 } 1067 } 1068 if (pmtudisc < 0) 1069 pmtudisc = IPV6_PMTUDISC_DO; 1070 } 1071 1072 if (pmtudisc >= 0) { 1073 if (setsockopt(icmp_sock, SOL_IPV6, IPV6_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) { 1074 perror("ping: IPV6_MTU_DISCOVER"); 1075 exit(2); 1076 } 1077 } 1078 1079 if ((options&F_STRICTSOURCE) && 1080 bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) { 1081 perror("ping: bind icmp socket"); 1082 exit(2); 1083 } 1084 1085 if (datalen >= sizeof(struct timeval) && (ni_query < 0)) { 1086 /* can we time transfer */ 1087 timing = 1; 1088 } 1089 packlen = datalen + 8 + 4096 + 40 + 8; /* 4096 for rthdr */ 1090 if (!(packet = (u_char *)malloc((u_int)packlen))) { 1091 fprintf(stderr, "ping: out of memory.\n"); 1092 exit(2); 1093 } 1094 1095 working_recverr = 1; 1096 hold = 1; 1097 if (setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVERR, (char *)&hold, sizeof(hold))) { 1098 fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n"); 1099 working_recverr = 0; 1100 } 1101 1102 /* Estimate memory eaten by single packet. It is rough estimate. 1103 * Actually, for small datalen's it depends on kernel side a lot. */ 1104 hold = datalen+8; 1105 hold += ((hold+511)/512)*(40+16+64+160); 1106 sock_setbufs(icmp_sock, hold); 1107 1108 if (!using_ping_socket) { 1109#ifdef __linux__ 1110 csum_offset = 2; 1111 sz_opt = sizeof(int); 1112 1113 err = setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, 1114 &csum_offset, sz_opt); 1115 if (err < 0) { 1116 /* checksum should be enabled by default and setting 1117 * this option might fail anyway. 1118 */ 1119 fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed" 1120 " - try to continue."); 1121 } 1122#endif 1123 1124 /* 1125 * select icmp echo reply as icmp type to receive 1126 */ 1127 1128 ICMP6_FILTER_SETBLOCKALL(&filter); 1129 1130 if (!working_recverr) { 1131 ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); 1132 ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter); 1133 ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter); 1134 ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter); 1135 } 1136 1137 if (niquery_is_enabled()) 1138 ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter); 1139 else 1140 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); 1141 1142 err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, 1143 &filter, sizeof(struct icmp6_filter)); 1144 1145 if (err < 0) { 1146 perror("setsockopt(ICMP6_FILTER)"); 1147 exit(2); 1148 } 1149 } 1150 1151 if (options & F_NOLOOP) { 1152 int loop = 0; 1153 if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 1154 &loop, sizeof(loop)) == -1) { 1155 perror ("can't disable multicast loopback"); 1156 exit(2); 1157 } 1158 } 1159 if (options & F_TTL) { 1160 if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1161 &ttl, sizeof(ttl)) == -1) { 1162 perror ("can't set multicast hop limit"); 1163 exit(2); 1164 } 1165 if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 1166 &ttl, sizeof(ttl)) == -1) { 1167 perror ("can't set unicast hop limit"); 1168 exit(2); 1169 } 1170 } 1171 1172 if (1) { 1173 int on = 1; 1174 if ( 1175#ifdef IPV6_RECVHOPLIMIT 1176 setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 1177 &on, sizeof(on)) == -1 && 1178 setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_2292HOPLIMIT, 1179 &on, sizeof(on)) == -1 1180#else 1181 setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_HOPLIMIT, 1182 &on, sizeof(on)) == -1 1183#endif 1184 ){ 1185 perror ("can't receive hop limit"); 1186 exit(2); 1187 } 1188 } 1189 1190 if (options & F_TCLASS) { 1191#ifdef IPV6_TCLASS 1192 if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_TCLASS, 1193 &tclass, sizeof(tclass)) == -1) { 1194 perror ("setsockopt(IPV6_TCLASS)"); 1195 exit(2); 1196 } 1197#else 1198 fprintf(stderr, "Traffic class is not supported.\n"); 1199#endif 1200 } 1201 1202 if (options&F_FLOWINFO) { 1203#ifdef IPV6_FLOWINFO_SEND 1204 int on = 1; 1205#endif 1206#ifdef IPV6_FLOWLABEL_MGR 1207 char freq_buf[CMSG_ALIGN(sizeof(struct in6_flowlabel_req)) + cmsglen]; 1208 struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf; 1209 int freq_len = sizeof(*freq); 1210#ifdef ENABLE_PING6_RTHDR 1211 if (srcrt) 1212 freq_len = CMSG_ALIGN(sizeof(*freq)) + srcrt->cmsg_len; 1213#endif 1214 memset(freq, 0, sizeof(*freq)); 1215 freq->flr_label = htonl(flowlabel & IPV6_FLOWINFO_FLOWLABEL); 1216 freq->flr_action = IPV6_FL_A_GET; 1217 freq->flr_flags = IPV6_FL_F_CREATE; 1218 freq->flr_share = IPV6_FL_S_EXCL; 1219 memcpy(&freq->flr_dst, &whereto.sin6_addr, 16); 1220#ifdef ENABLE_PING6_RTHDR 1221 if (srcrt) 1222 memcpy(freq_buf + CMSG_ALIGN(sizeof(*freq)), srcrt, srcrt->cmsg_len); 1223#endif 1224 if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, 1225 freq, freq_len) == -1) { 1226 perror ("can't set flowlabel"); 1227 exit(2); 1228 } 1229 flowlabel = freq->flr_label; 1230#ifdef ENABLE_PING6_RTHDR 1231 if (srcrt) { 1232 cmsglen = (char*)srcrt - (char*)cmsgbuf; 1233 srcrt = NULL; 1234 } 1235#endif 1236#else 1237 fprintf(stderr, "Flow labels are not supported.\n"); 1238 exit(2); 1239#endif 1240 1241#ifdef IPV6_FLOWINFO_SEND 1242 whereto.sin6_flowinfo = flowlabel; 1243 if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, 1244 &on, sizeof(on)) == -1) { 1245 perror ("can't send flowinfo"); 1246 exit(2); 1247 } 1248#else 1249 fprintf(stderr, "Flowinfo is not supported.\n"); 1250 exit(2); 1251#endif 1252 } 1253 1254 printf("PING %s(%s) ", hostname, pr_addr(&whereto.sin6_addr)); 1255 if (flowlabel) 1256 printf(", flow 0x%05x, ", (unsigned)ntohl(flowlabel)); 1257 if (device || (options&F_STRICTSOURCE)) { 1258 printf("from %s %s: ", 1259 pr_addr_n(&source.sin6_addr), device ? : ""); 1260 } 1261 printf("%d data bytes\n", datalen); 1262 1263 setup(icmp_sock); 1264 1265 drop_capabilities(); 1266 1267 main_loop(icmp_sock, packet, packlen); 1268} 1269 1270int receive_error_msg() 1271{ 1272 int res; 1273 char cbuf[512]; 1274 struct iovec iov; 1275 struct msghdr msg; 1276 struct cmsghdr *cmsg; 1277 struct sock_extended_err *e; 1278 struct icmp6_hdr icmph; 1279 struct sockaddr_in6 target; 1280 int net_errors = 0; 1281 int local_errors = 0; 1282 int saved_errno = errno; 1283 1284 iov.iov_base = &icmph; 1285 iov.iov_len = sizeof(icmph); 1286 msg.msg_name = (void*)⌖ 1287 msg.msg_namelen = sizeof(target); 1288 msg.msg_iov = &iov; 1289 msg.msg_iovlen = 1; 1290 msg.msg_flags = 0; 1291 msg.msg_control = cbuf; 1292 msg.msg_controllen = sizeof(cbuf); 1293 1294 res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT); 1295 if (res < 0) 1296 goto out; 1297 1298 e = NULL; 1299 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 1300 if (cmsg->cmsg_level == SOL_IPV6) { 1301 if (cmsg->cmsg_type == IPV6_RECVERR) 1302 e = (struct sock_extended_err *)CMSG_DATA(cmsg); 1303 } 1304 } 1305 if (e == NULL) 1306 abort(); 1307 1308 if (e->ee_origin == SO_EE_ORIGIN_LOCAL) { 1309 local_errors++; 1310 if (options & F_QUIET) 1311 goto out; 1312 if (options & F_FLOOD) 1313 write_stdout("E", 1); 1314 else if (e->ee_errno != EMSGSIZE) 1315 fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno)); 1316 else 1317 fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info); 1318 nerrors++; 1319 } else if (e->ee_origin == SO_EE_ORIGIN_ICMP6) { 1320 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)(e+1); 1321 1322 if (res < sizeof(icmph) || 1323 memcmp(&target.sin6_addr, &whereto.sin6_addr, 16) || 1324 icmph.icmp6_type != ICMP6_ECHO_REQUEST || 1325 !is_ours(icmph.icmp6_id)) { 1326 /* Not our error, not an error at all. Clear. */ 1327 saved_errno = 0; 1328 goto out; 1329 } 1330 1331 net_errors++; 1332 nerrors++; 1333 if (options & F_QUIET) 1334 goto out; 1335 if (options & F_FLOOD) { 1336 write_stdout("\bE", 2); 1337 } else { 1338 print_timestamp(); 1339 printf("From %s icmp_seq=%u ", pr_addr(&sin6->sin6_addr), ntohs(icmph.icmp6_seq)); 1340 pr_icmph(e->ee_type, e->ee_code, e->ee_info); 1341 putchar('\n'); 1342 fflush(stdout); 1343 } 1344 } 1345 1346out: 1347 errno = saved_errno; 1348 return net_errors ? : -local_errors; 1349} 1350 1351/* 1352 * pinger -- 1353 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 1354 * will be added on by the kernel. The ID field is our UNIX process ID, 1355 * and the sequence number is an ascending integer. The first 8 bytes 1356 * of the data portion are used to hold a UNIX "timeval" struct in VAX 1357 * byte-order, to compute the round-trip time. 1358 */ 1359int build_echo(__u8 *_icmph) 1360{ 1361 struct icmp6_hdr *icmph; 1362 int cc; 1363 1364 icmph = (struct icmp6_hdr *)_icmph; 1365 icmph->icmp6_type = ICMP6_ECHO_REQUEST; 1366 icmph->icmp6_code = 0; 1367 icmph->icmp6_cksum = 0; 1368 icmph->icmp6_seq = htons(ntransmitted+1); 1369 icmph->icmp6_id = ident; 1370 1371 if (timing) 1372 gettimeofday((struct timeval *)&outpack[8], 1373 (struct timezone *)NULL); 1374 1375 cc = datalen + 8; /* skips ICMP portion */ 1376 1377 return cc; 1378} 1379 1380 1381int build_niquery(__u8 *_nih) 1382{ 1383 struct ni_hdr *nih; 1384 int cc; 1385 1386 nih = (struct ni_hdr *)_nih; 1387 nih->ni_cksum = 0; 1388 1389 nih->ni_type = ICMPV6_NI_QUERY; 1390 cc = sizeof(*nih); 1391 datalen = 0; 1392 1393 niquery_fill_nonce(ntransmitted + 1, nih->ni_nonce); 1394 nih->ni_code = ni_subject_type; 1395 nih->ni_qtype = htons(ni_query); 1396 nih->ni_flags = ni_flag; 1397 memcpy(nih + 1, ni_subject, ni_subject_len); 1398 cc += ni_subject_len; 1399 1400 return cc; 1401} 1402 1403int send_probe(void) 1404{ 1405 int len, cc; 1406 1407 rcvd_clear(ntransmitted + 1); 1408 1409 if (niquery_is_enabled()) 1410 len = build_niquery(outpack); 1411 else 1412 len = build_echo(outpack); 1413 1414 if (cmsglen == 0) { 1415 cc = sendto(icmp_sock, (char *)outpack, len, confirm, 1416 (struct sockaddr *) &whereto, 1417 sizeof(struct sockaddr_in6)); 1418 } else { 1419 struct msghdr mhdr; 1420 struct iovec iov; 1421 1422 iov.iov_len = len; 1423 iov.iov_base = outpack; 1424 1425 memset(&mhdr, 0, sizeof(mhdr)); 1426 mhdr.msg_name = &whereto; 1427 mhdr.msg_namelen = sizeof(struct sockaddr_in6); 1428 mhdr.msg_iov = &iov; 1429 mhdr.msg_iovlen = 1; 1430 mhdr.msg_control = cmsgbuf; 1431 mhdr.msg_controllen = cmsglen; 1432 1433 cc = sendmsg(icmp_sock, &mhdr, confirm); 1434 } 1435 confirm = 0; 1436 1437 return (cc == len ? 0 : cc); 1438} 1439 1440void pr_echo_reply(__u8 *_icmph, int cc) 1441{ 1442 struct icmp6_hdr *icmph = (struct icmp6_hdr *) _icmph; 1443 printf(" icmp_seq=%u", ntohs(icmph->icmp6_seq)); 1444}; 1445 1446static void putchar_safe(char c) 1447{ 1448 if (isprint(c)) 1449 putchar(c); 1450 else 1451 printf("\\%03o", c); 1452} 1453 1454void pr_niquery_reply_name(struct ni_hdr *nih, int len) 1455{ 1456 __u8 *h = (__u8 *)(nih + 1); 1457 __u8 *p = h + 4; 1458 __u8 *end = (__u8 *)nih + len; 1459 int continued = 0; 1460 char buf[1024]; 1461 int ret; 1462 1463 len -= sizeof(struct ni_hdr) + 4; 1464 1465 if (len < 0) { 1466 printf(" parse error (too short)"); 1467 return; 1468 } 1469 while (p < end) { 1470 int fqdn = 1; 1471 int i; 1472 1473 memset(buf, 0xff, sizeof(buf)); 1474 1475 if (continued) 1476 putchar(','); 1477 1478 ret = dn_expand(h, end, p, buf, sizeof(buf)); 1479 if (ret < 0) { 1480 printf(" parse error (truncated)"); 1481 break; 1482 } 1483 if (p + ret < end && *(p + ret) == '\0') 1484 fqdn = 0; 1485 1486 putchar(' '); 1487 for (i = 0; i < strlen(buf); i++) 1488 putchar_safe(buf[i]); 1489 if (fqdn) 1490 putchar('.'); 1491 1492 p += ret + !fqdn; 1493 1494 continued = 1; 1495 } 1496} 1497 1498void pr_niquery_reply_addr(struct ni_hdr *nih, int len) 1499{ 1500 __u8 *h = (__u8 *)(nih + 1); 1501 __u8 *p = h + 4; 1502 __u8 *end = (__u8 *)nih + len; 1503 int af; 1504 int aflen; 1505 int continued = 0; 1506 int truncated; 1507 char buf[1024]; 1508 1509 switch (ntohs(nih->ni_qtype)) { 1510 case NI_QTYPE_IPV4ADDR: 1511 af = AF_INET; 1512 aflen = sizeof(struct in_addr); 1513 truncated = nih->ni_flags & NI_IPV6ADDR_F_TRUNCATE; 1514 break; 1515 case NI_QTYPE_IPV6ADDR: 1516 af = AF_INET6; 1517 aflen = sizeof(struct in6_addr); 1518 truncated = nih->ni_flags & NI_IPV4ADDR_F_TRUNCATE; 1519 break; 1520 default: 1521 /* should not happen */ 1522 af = aflen = truncated = 0; 1523 } 1524 p = h; 1525 if (len < 0) { 1526 printf(" parse error (too short)"); 1527 return; 1528 } 1529 1530 while (p < end) { 1531 if (continued) 1532 putchar(','); 1533 1534 if (p + sizeof(__u32) + aflen > end) { 1535 printf(" parse error (truncated)"); 1536 break; 1537 } 1538 if (!inet_ntop(af, p + sizeof(__u32), buf, sizeof(buf))) 1539 printf(" unexpeced error in inet_ntop(%s)", 1540 strerror(errno)); 1541 else 1542 printf(" %s", buf); 1543 p += sizeof(__u32) + aflen; 1544 1545 continued = 1; 1546 } 1547 if (truncated) 1548 printf(" (truncated)"); 1549} 1550 1551void pr_niquery_reply(__u8 *_nih, int len) 1552{ 1553 struct ni_hdr *nih = (struct ni_hdr *)_nih; 1554 1555 switch (nih->ni_code) { 1556 case NI_SUCCESS: 1557 switch (ntohs(nih->ni_qtype)) { 1558 case NI_QTYPE_NAME: 1559 pr_niquery_reply_name(nih, len); 1560 break; 1561 case NI_QTYPE_IPV4ADDR: 1562 case NI_QTYPE_IPV6ADDR: 1563 pr_niquery_reply_addr(nih, len); 1564 break; 1565 default: 1566 printf(" unknown qtype(0x%02x)", ntohs(nih->ni_qtype)); 1567 } 1568 break; 1569 case NI_REFUSED: 1570 printf(" refused"); 1571 break; 1572 case NI_UNKNOWN: 1573 printf(" unknown"); 1574 break; 1575 default: 1576 printf(" unknown code(%02x)", ntohs(nih->ni_code)); 1577 } 1578 printf("; seq=%u;", ntohsp((__u16*)nih->ni_nonce)); 1579} 1580 1581/* 1582 * parse_reply -- 1583 * Print out the packet, if it came from us. This logic is necessary 1584 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 1585 * which arrive ('tis only fair). This permits multiple copies of this 1586 * program to be run without having intermingled output (or statistics!). 1587 */ 1588int 1589parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv) 1590{ 1591 struct sockaddr_in6 *from = addr; 1592 __u8 *buf = msg->msg_iov->iov_base; 1593 struct cmsghdr *c; 1594 struct icmp6_hdr *icmph; 1595 int hops = -1; 1596 1597 for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) { 1598 if (c->cmsg_level != SOL_IPV6) 1599 continue; 1600 switch(c->cmsg_type) { 1601 case IPV6_HOPLIMIT: 1602#ifdef IPV6_2292HOPLIMIT 1603 case IPV6_2292HOPLIMIT: 1604#endif 1605 if (c->cmsg_len < CMSG_LEN(sizeof(int))) 1606 continue; 1607 memcpy(&hops, CMSG_DATA(c), sizeof(hops)); 1608 } 1609 } 1610 1611 1612 /* Now the ICMP part */ 1613 1614 icmph = (struct icmp6_hdr *) buf; 1615 if (cc < 8) { 1616 if (options & F_VERBOSE) 1617 fprintf(stderr, "ping: packet too short (%d bytes)\n", cc); 1618 return 1; 1619 } 1620 1621 if (icmph->icmp6_type == ICMP6_ECHO_REPLY) { 1622 if (!is_ours(icmph->icmp6_id)) 1623 return 1; 1624 if (gather_statistics((__u8*)icmph, sizeof(*icmph), cc, 1625 ntohs(icmph->icmp6_seq), 1626 hops, 0, tv, pr_addr(&from->sin6_addr), 1627 pr_echo_reply)) 1628 return 0; 1629 } else if (icmph->icmp6_type == ICMPV6_NI_REPLY) { 1630 struct ni_hdr *nih = (struct ni_hdr *)icmph; 1631 int seq = niquery_check_nonce(nih->ni_nonce); 1632 if (seq < 0) 1633 return 1; 1634 if (gather_statistics((__u8*)icmph, sizeof(*icmph), cc, 1635 seq, 1636 hops, 0, tv, pr_addr(&from->sin6_addr), 1637 pr_niquery_reply)) 1638 return 0; 1639 } else { 1640 int nexthdr; 1641 struct ip6_hdr *iph1 = (struct ip6_hdr*)(icmph+1); 1642 struct icmp6_hdr *icmph1 = (struct icmp6_hdr *)(iph1+1); 1643 1644 /* We must not ever fall here. All the messages but 1645 * echo reply are blocked by filter and error are 1646 * received with IPV6_RECVERR. Ugly code is preserved 1647 * however, just to remember what crap we avoided 1648 * using RECVRERR. :-) 1649 */ 1650 1651 if (cc < 8+sizeof(struct ip6_hdr)+8) 1652 return 1; 1653 1654 if (memcmp(&iph1->ip6_dst, &whereto.sin6_addr, 16)) 1655 return 1; 1656 1657 nexthdr = iph1->ip6_nxt; 1658 1659 if (nexthdr == 44) { 1660 nexthdr = *(__u8*)icmph1; 1661 icmph1++; 1662 } 1663 if (nexthdr == IPPROTO_ICMPV6) { 1664 if (icmph1->icmp6_type != ICMP6_ECHO_REQUEST || 1665 !is_ours(icmph1->icmp6_id)) 1666 return 1; 1667 acknowledge(ntohs(icmph1->icmp6_seq)); 1668 if (working_recverr) 1669 return 0; 1670 nerrors++; 1671 if (options & F_FLOOD) { 1672 write_stdout("\bE", 2); 1673 return 0; 1674 } 1675 print_timestamp(); 1676 printf("From %s: icmp_seq=%u ", pr_addr(&from->sin6_addr), ntohs(icmph1->icmp6_seq)); 1677 } else { 1678 /* We've got something other than an ECHOREPLY */ 1679 if (!(options & F_VERBOSE) || uid) 1680 return 1; 1681 print_timestamp(); 1682 printf("From %s: ", pr_addr(&from->sin6_addr)); 1683 } 1684 pr_icmph(icmph->icmp6_type, icmph->icmp6_code, ntohl(icmph->icmp6_mtu)); 1685 } 1686 1687 if (!(options & F_FLOOD)) { 1688 if (options & F_AUDIBLE) 1689 putchar('\a'); 1690 putchar('\n'); 1691 fflush(stdout); 1692 } else { 1693 putchar('\a'); 1694 fflush(stdout); 1695 } 1696 return 0; 1697} 1698 1699 1700int pr_icmph(__u8 type, __u8 code, __u32 info) 1701{ 1702 switch(type) { 1703 case ICMP6_DST_UNREACH: 1704 printf("Destination unreachable: "); 1705 switch (code) { 1706 case ICMP6_DST_UNREACH_NOROUTE: 1707 printf("No route"); 1708 break; 1709 case ICMP6_DST_UNREACH_ADMIN: 1710 printf("Administratively prohibited"); 1711 break; 1712 case ICMP6_DST_UNREACH_BEYONDSCOPE: 1713 printf("Beyond scope of source address"); 1714 break; 1715 case ICMP6_DST_UNREACH_ADDR: 1716 printf("Address unreachable"); 1717 break; 1718 case ICMP6_DST_UNREACH_NOPORT: 1719 printf("Port unreachable"); 1720 break; 1721 default: 1722 printf("Unknown code %d", code); 1723 break; 1724 } 1725 break; 1726 case ICMP6_PACKET_TOO_BIG: 1727 printf("Packet too big: mtu=%u", info); 1728 if (code) 1729 printf(", code=%d", code); 1730 break; 1731 case ICMP6_TIME_EXCEEDED: 1732 printf("Time exceeded: "); 1733 if (code == ICMP6_TIME_EXCEED_TRANSIT) 1734 printf("Hop limit"); 1735 else if (code == ICMP6_TIME_EXCEED_REASSEMBLY) 1736 printf("Defragmentation failure"); 1737 else 1738 printf("code %d", code); 1739 break; 1740 case ICMP6_PARAM_PROB: 1741 printf("Parameter problem: "); 1742 if (code == ICMP6_PARAMPROB_HEADER) 1743 printf("Wrong header field "); 1744 else if (code == ICMP6_PARAMPROB_NEXTHEADER) 1745 printf("Unknown header "); 1746 else if (code == ICMP6_PARAMPROB_OPTION) 1747 printf("Unknown option "); 1748 else 1749 printf("code %d ", code); 1750 printf ("at %u", info); 1751 break; 1752 case ICMP6_ECHO_REQUEST: 1753 printf("Echo request"); 1754 break; 1755 case ICMP6_ECHO_REPLY: 1756 printf("Echo reply"); 1757 break; 1758 case MLD_LISTENER_QUERY: 1759 printf("MLD Query"); 1760 break; 1761 case MLD_LISTENER_REPORT: 1762 printf("MLD Report"); 1763 break; 1764 case MLD_LISTENER_REDUCTION: 1765 printf("MLD Reduction"); 1766 break; 1767 default: 1768 printf("unknown icmp type: %u", type); 1769 1770 } 1771 return 0; 1772} 1773 1774#include <linux/filter.h> 1775 1776void install_filter(void) 1777{ 1778 static int once; 1779 static struct sock_filter insns[] = { 1780 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 4), /* Load icmp echo ident */ 1781 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */ 1782 BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */ 1783 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0), /* Load icmp type */ 1784 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */ 1785 BPF_STMT(BPF_RET|BPF_K, ~0U), /* No. It passes. This must not happen. */ 1786 BPF_STMT(BPF_RET|BPF_K, 0), /* Echo with wrong ident. Reject. */ 1787 }; 1788 static struct sock_fprog filter = { 1789 sizeof insns / sizeof(insns[0]), 1790 insns 1791 }; 1792 1793 if (once) 1794 return; 1795 once = 1; 1796 1797 /* Patch bpflet for current identifier. */ 1798 insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(ident), 0, 1); 1799 1800 if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) 1801 perror("WARNING: failed to install socket filter\n"); 1802} 1803 1804 1805/* 1806 * pr_addr -- 1807 * Return an ascii host address as a dotted quad and optionally with 1808 * a hostname. 1809 */ 1810char * pr_addr(struct in6_addr *addr) 1811{ 1812 struct hostent *hp = NULL; 1813 static char *s; 1814 1815#ifdef USE_IDN 1816 free(s); 1817#endif 1818 1819 in_pr_addr = !setjmp(pr_addr_jmp); 1820 1821 if (!(exiting || options&F_NUMERIC)) 1822 hp = gethostbyaddr((__u8*)addr, sizeof(struct in6_addr), AF_INET6); 1823 1824 in_pr_addr = 0; 1825 1826 if (!hp 1827#ifdef USE_IDN 1828 || idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS 1829#endif 1830 ) 1831 s = NULL; 1832 1833 return hp ? (s ? s : hp->h_name) : pr_addr_n(addr); 1834} 1835 1836char * pr_addr_n(struct in6_addr *addr) 1837{ 1838 static char str[64]; 1839 inet_ntop(AF_INET6, addr, str, sizeof(str)); 1840 return str; 1841} 1842 1843#define USAGE_NEWLINE "\n " 1844 1845void usage(void) 1846{ 1847 fprintf(stderr, 1848 "Usage: ping6" 1849 " [-" 1850 "aAbBdDfhLnOqrRUvV" 1851 "]" 1852 " [-c count]" 1853 " [-i interval]" 1854 " [-I interface]" 1855 USAGE_NEWLINE 1856 " [-l preload]" 1857 " [-m mark]" 1858 " [-M pmtudisc_option]" 1859 USAGE_NEWLINE 1860 " [-N nodeinfo_option]" 1861 " [-p pattern]" 1862 " [-Q tclass]" 1863 " [-s packetsize]" 1864 USAGE_NEWLINE 1865 " [-S sndbuf]" 1866 " [-t ttl]" 1867 " [-T timestamp_option]" 1868 " [-w deadline]" 1869 USAGE_NEWLINE 1870 " [-W timeout]" 1871#ifdef ENABLE_PING6_RTHDR 1872 " [hop1 ...]" 1873#endif 1874 " destination" 1875 "\n" 1876 ); 1877 exit(2); 1878} 1879