STATIC int open_rtadv_socket(void) { struct icmp6_filter filt; int sockfd; /* open socket */ sockfd = ICMPv6SocketOpen(TRUE); if (sockfd < 0) { my_log_fl(LOG_ERR, "error opening socket: %s", strerror(errno)); goto failed; } /* accept only router advertisement messages */ ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); if (setsockopt(sockfd, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) { my_log_fl(LOG_ERR, "setsockopt(ICMP6_FILTER): %s", strerror(errno)); goto failed; } return (sockfd); failed: if (sockfd >= 0) { close(sockfd); } return (-1); }
int start_client() { struct icmp6_filter filter; int val; // pthread_mutexattr_t mattrs; // pthread_t chart; init_my_npm(); // pthread_create(&chart, NULL, input_thread, (void *)NULL); sock_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock_fd < 0) { printf("Unable to open ICMPv6 socket! " "Do you have root permissions?\n"); } val = 1; if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0) { printf("Setsockopt() failed in client.c -- 1\n") ; return -1; } if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)) < 0) { printf("Setsockopt() failed in client.c -- 2\n") ; return -1; } ICMP6_FILTER_SETBLOCKALL(&filter); // ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_SOLICIT, &filter); // ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter); if (setsockopt(sock_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(struct icmp6_filter)) < 0) { printf("Setsockopt() failed in client.c -- 3\n") ; return -1; } val = 2 ; /* create ICMP listener thread */ // pthread_mutexattr_init(&mattrs); // pthread_mutexattr_settype(&mattrs, PTHREAD_MUTEX_NORMAL); /* if (pthread_mutex_init(&send_mutex, &mattrs) || pthread_rwlock_init(&handler_lock, NULL) || pthread_create(&icmp6_listener, NULL, icmp6_listen, &sock_fd))*/ if(pthread_create(&icmp6_listener, NULL, icmp6_listen, &sock_fd)) { return -1; } return 0; }
filter(bool block) { if (block) { ICMP6_FILTER_SETBLOCKALL(&_filter); } else { ICMP6_FILTER_SETPASSALL(&_filter); } }
filter(bool block, uint except_value_type) { if (block) { ICMP6_FILTER_SETBLOCKALL(&_filter); ICMP6_FILTER_SETPASS(except_value_type, &_filter); } else { ICMP6_FILTER_SETPASSALL(&_filter); ICMP6_FILTER_SETBLOCK(except_value_type, &_filter); } }
int icmp6_init(void) { struct icmp6_filter filter; pthread_mutexattr_t mattrs; int val; icmp6_sock.fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (icmp6_sock.fd < 0) { syslog(LOG_ERR, "Unable to open ICMPv6 socket! " "Do you have root permissions?"); return icmp6_sock.fd; } val = 1; if (setsockopt(icmp6_sock.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0) return -1; if (setsockopt(icmp6_sock.fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)) < 0) return -1; ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); if (is_ha()) { ICMP6_FILTER_SETPASS(MIP_PREFIX_SOLICIT, &filter); ICMP6_FILTER_SETPASS(MIP_HA_DISCOVERY_REQUEST, &filter); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); } if (is_mn()) { ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter); ICMP6_FILTER_SETPASS(MIP_PREFIX_ADVERT, &filter); ICMP6_FILTER_SETPASS(MIP_HA_DISCOVERY_REPLY, &filter); ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter); } if (setsockopt(icmp6_sock.fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(struct icmp6_filter)) < 0) return -1; val = 2; if (setsockopt(icmp6_sock.fd, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)) < 0) return -1; /* create ICMP listener thread */ pthread_mutexattr_init(&mattrs); pthread_mutexattr_settype(&mattrs, PTHREAD_MUTEX_FAST_NP); if (pthread_mutex_init(&icmp6_sock.send_mutex, &mattrs) || pthread_rwlock_init(&handler_lock, NULL) || pthread_create(&icmp6_listener, NULL, icmp6_listen, NULL)) return -1; return 0; }
int dhcp_network_icmp6_bind_router_solicitation(int index) { struct icmp6_filter filter = { }; struct ipv6_mreq mreq = { .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, .ipv6mr_interface = index, }; _cleanup_close_ int s = -1; int r, zero = 0, hops = 255; s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); if (s < 0) return -errno; ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)); if (r < 0) return -errno; /* RFC 3315, section 6.7, bullet point 2 may indicate that an IPV6_PKTINFO socket option also applies for ICMPv6 multicast. Empirical experiments indicates otherwise and therefore an IPV6_MULTICAST_IF socket option is used here instead */ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)); if (r < 0) return -errno; r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)); if (r < 0) return -errno; r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)); if (r < 0) return -errno; r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); if (r < 0) return -errno; r = s; s = -1; return r; }
int init_router(void) { // Open ICMPv6 socket int sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6); if (sock < 0 && errno != EAFNOSUPPORT) { syslog(LOG_ERR, "Failed to open RAW-socket: %s", strerror(errno)); return -1; } // Let the kernel compute our checksums int val = 2; setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)); // This is required by RFC 4861 val = 255; setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)); setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)); // We need to know the source interface val = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)); // Don't loop back val = 0; setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof(val)); // Filter ICMPv6 package types struct icmp6_filter filt; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)); // Register socket router_event.uloop.fd = sock; odhcpd_register(&router_event); if (!(fp_route = fopen("/proc/net/ipv6_route", "r"))) syslog(LOG_ERR, "Failed to open routing table: %s", strerror(errno)); signal(SIGUSR1, sigusr1_refresh); return 0; }
static int icmp_socket(char *name) { struct icmp6_filter filter; int sock = -1; sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if ( sock > 0 ) { ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT,&filter); if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(struct icmp6_filter)) < 0 ) { perror("setsockopt: %s"); close(sock); sock = -1; } else { if ( name ) { if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1) < 0 ) { perror("setsockopt:"); close(sock); sock = -1; } } } } else { perror("socket"); } return sock; }
void init_v6() { #ifdef IPV6 int on = 1; if (verbose == 0) { /* install a filter that only passes ICMP6_ECHO_REPLY unless verbose */ struct icmp6_filter myfilt; ICMP6_FILTER_SETBLOCKALL(&myfilt); ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &myfilt); setsockopt(sockfd, IPPROTO_IPV6, ICMP6_FILTER, &myfilt, sizeof(myfilt)); /* ignore error return; the filter is an optimization */ } /* ignore error returned below; we just won't receive the hop limit */ #ifdef IPV6_RECVHOPLIMIT /* RFC 3542 */ setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)); #else /* RFC 2292 */ setsockopt(sockfd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)); #endif #endif }
static int icmp6_sock_open(int *sock_p) { int sock; struct icmp6_filter flt; int ret; int err; int val; sock = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock == -1) { teamd_log_err("Failed to create ICMP6 socket."); return -errno; } ICMP6_FILTER_SETBLOCKALL(&flt); ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &flt, sizeof(flt)); if (ret == -1) { teamd_log_err("Failed to setsockopt ICMP6_FILTER."); err = -errno; goto close_sock; } val = 255; ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)); if (ret == -1) { teamd_log_err("Failed to setsockopt IPV6_MULTICAST_HOPS."); err = -errno; goto close_sock; } *sock_p = sock; return 0; close_sock: close(sock); return err; }
/* functional tests */ void icmp6_ft(void) { struct icmp6_filter i6f; int sall, sf; int i; sall = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sall < 0) { tst_resm(TBROK | TERRNO, "icmp6_ft socket: can't create sall socket"); return; } ICMP6_FILTER_SETPASSALL(&i6f); if (setsockopt(sall, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, sizeof(i6f)) < 0) { tst_resm(TBROK | TERRNO, "setsockopt pass all ICMP6_FILTER failed"); } sf = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sf < 0) { tst_resm(TBROK | TERRNO, "icmp6_ft socket: can't create test socket"); return; } int rv; for (i = 0; i < FTCOUNT; ++i) { rv = -1; switch (ftab[i].ft_test) { case T_SETPASS: ICMP6_FILTER_SETBLOCKALL(&i6f); ICMP6_FILTER_SETPASS(ftab[i].ft_flttype, &i6f); break; case T_SETPASSALL: ICMP6_FILTER_SETPASSALL(&i6f); break; case T_SETBLOCK: ICMP6_FILTER_SETPASSALL(&i6f); ICMP6_FILTER_SETBLOCK(ftab[i].ft_flttype, &i6f); break; case T_SETBLOCKALL: ICMP6_FILTER_SETBLOCKALL(&i6f); break; case T_WILLBLOCK: ICMP6_FILTER_SETPASSALL(&i6f); ICMP6_FILTER_SETBLOCK(ftab[i].ft_flttype, &i6f); rv = ICMP6_FILTER_WILLBLOCK(ftab[i].ft_sndtype, &i6f); break; case T_WILLPASS: ICMP6_FILTER_SETBLOCKALL(&i6f); ICMP6_FILTER_SETPASS(ftab[i].ft_flttype, &i6f); rv = ICMP6_FILTER_WILLPASS(ftab[i].ft_sndtype, &i6f); break; default: tst_resm(TBROK, "%s: unknown test type %d", ftab[i].ft_tname, ftab[i].ft_test); continue; } if (ftab[i].ft_test != T_WILLBLOCK && ftab[i].ft_test != T_WILLPASS) { if (setsockopt(sf, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, sizeof(i6f)) < 0) { tst_resm(TFAIL | TERRNO, "setsockopt ICMP6_FILTER"); continue; } if (ic6_send1(ftab[i].ft_tname, ftab[i].ft_sndtype)) continue; rv = ic6_recv1(ftab[i].ft_tname, sall, sf); } else rv = -1; if (rv < 0) continue; if (rv != ftab[i].ft_expected) tst_resm(TFAIL, "%s: rv %d != expected %d", ftab[i].ft_tname, rv, ftab[i].ft_expected); else tst_resm(TPASS, ftab[i].ft_tname); } }
int ndisc_do_dad(int ifi, struct in6_addr *addr, int do_ll) { struct in6_pktinfo pinfo; struct sockaddr_in6 saddr; struct nd_neighbor_advert *hdr; struct icmp6_filter filter; struct in6_addr solicit, ll; unsigned char msg[MAX_PKT_LEN]; int hoplimit, sock = -1, ret, val = 1, err = -1; fd_set rset; struct timeval tv; ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter); sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock < 0) { dbg("socket: %s\n", strerror(errno)); goto end; } if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0) { dbg("cannot set IPV6_RECVPKTINFO: %s\n", strerror(errno)); goto end; } if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)) < 0) { dbg("cannot set IPV6_RECVHOPLIMIT: %s\n", strerror(errno)); goto end; } if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(struct icmp6_filter)) < 0) { dbg("cannot set ICMPV6_FILTER: %s\n", strerror(errno)); goto end; } ipv6_addr_solict_mult(addr, &solicit); if (if_mc_group(sock, ifi, &in6addr_all_nodes_mc, IPV6_JOIN_GROUP)) { dbg("cannot join all node mc\n"); goto end; } if (if_mc_group(sock, ifi, &solicit, IPV6_JOIN_GROUP)) { dbg("cannot joing slicit node mc\n"); goto end; } if (ndisc_send_ns(ifi, addr) <= 0) { dbg("Error at sending NS\n"); goto end; } if (do_ll) { ipv6_addr_llocal(addr, &ll); if (ndisc_send_ns(ifi, &ll) <= 0) { dbg("Error at sending NS (link-local target)\n"); goto end; } } FD_ZERO(&rset); FD_SET(sock, &rset); tv.tv_sec = DAD_TIMEOUT; tv.tv_usec = 0; for (;;) { /* Note on portability: we assume that tv is modified to show the time left which is AFAIK true only in Linux timeout */ if (select(sock+1, &rset, NULL, NULL, &tv) == 0) { dbg("Dad success\n"); err = 0; break; } if (!FD_ISSET(sock, &rset)) continue; /* We got an ICMPv6 packet */ ret = icmp6_recv(sock, msg, sizeof(msg), &saddr, &pinfo, &hoplimit); if (ret < 0) continue; hdr = (struct nd_neighbor_advert *)msg; if (hdr->nd_na_code != 0) continue; if (IN6_ARE_ADDR_EQUAL(addr, &hdr->nd_na_target) || (do_ll && IN6_ARE_ADDR_EQUAL(&ll, &hdr->nd_na_target))) { dbg("Failure\n"); break; } } end: if (sock >= 0) close(sock); return err; }
int setup_ra_socket() { int s, i, rc, one = 1, ff = 255; struct icmp6_filter filter; if(ra_socket >= 0) { close(ra_socket); ra_socket = -1; } s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if(s < 0) return -1; rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ff, sizeof(ff)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ff, sizeof(ff)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); if(rc < 0) goto fail; for(i = 0; i < numinterfaces; i++) { struct ipv6_mreq mreq; const unsigned char all_routers[16] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}; if(interfaces[i].ifindex <= 0) continue; memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, &all_routers, 16); mreq.ipv6mr_interface = interfaces[i].ifindex; rc = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) goto fail; } ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); rc = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFD, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); if(rc < 0) goto fail; rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); if(rc < 0) goto fail; ra_socket = s; return s; fail: return -1; }
int SetICMPv6SockOpt(int iSockfd) { int val; int ret = -1; struct icmp6_filter stIcmpFlt; /* 接收其他报文信息 */ val = 1; ret = setsockopt(iSockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); if (0 > ret) { perror("setsockopt (IPV6_RECVPKTINFO) error "); return (-1); } /* 设置成2表示由内核完成校验和检查???? */ #if 0 val = 2; ret = setsockopt(iSockfd, SOL_IPV6, IPV6_CHECKSUM, &val, sizeof(val)); if (0 > ret) { perror("setsockopt (IPV6_CHECKSUM) error"); return (-1); } #endif /* 控制本socket发送出去的报文的跳数为255 */ val = 255; ret = setsockopt(iSockfd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)); if (0 > ret) { perror("setsockopt (IPV6_UNICAST_HOPS) error"); return (-1); } /* 设置本socket发送出去的所有多播报文的跳数为255 */ val = 255; ret = setsockopt(iSockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)); if (0 > ret) { perror("setsockopt (IPV6_MULTICAST_HOPS) error"); return (-1); } /* 设置本属性从而告诉recvmsg函数将收到的报文的hop也带上来给用户态,本属性默认没开启从而用户态收不到对应的hop */ val = 1; ret = setsockopt(iSockfd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)); if (0 > ret) { perror("setsockopt (IPV6_RECVHOPLIMIT) error"); return (-1); } /* 设置RAW过滤,只接收RA报文 */ /*BEGIN 2032203980 m00182044 2012-06-10 modify*/ #if 1 /*END 2032203980 m00182044 2012-06-10 modify*/ ICMP6_FILTER_SETBLOCKALL(&stIcmpFlt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &stIcmpFlt); ret = setsockopt(iSockfd, IPPROTO_ICMPV6, ICMP6_FILTER, &stIcmpFlt, sizeof(stIcmpFlt)); if (0 > ret) { perror("setsockopt (ICMP6_FILTER) error"); return (-1); } #endif // TODO: set socket no-block return 0; }
int main(int argc, char *argv[]) { int ch, hold, packlen; u_char *packet; char *target; struct addrinfo hints, *ai; int gai; struct sockaddr_in6 firsthop; int socket_errno = 0; struct icmp6_filter filter; int err; #ifdef __linux__ int csum_offset, sz_opt; #endif static uint32_t scope_id = 0; #ifdef ANDROID android_check_security(); #endif limit_capabilities(); #ifdef USE_IDN setlocale(LC_ALL, ""); #endif icmp_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); if (icmp_sock < 0) { enable_capability_raw(); icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); socket_errno = errno; disable_capability_raw(); using_ping_socket = 0; } source.sin6_family = AF_INET6; memset(&firsthop, 0, sizeof(firsthop)); firsthop.sin6_family = AF_INET6; preload = 1; while ((ch = getopt(argc, argv, COMMON_OPTSTR "F:N:")) != EOF) { switch(ch) { case 'F': flowlabel = hextoui(optarg); if (errno || (flowlabel & ~IPV6_FLOWINFO_FLOWLABEL)) { fprintf(stderr, "ping: Invalid flowinfo %s\n", optarg); exit(2); } options |= F_FLOWINFO; break; case 'Q': tclass = hextoui(optarg); if (errno || (tclass & ~0xff)) { fprintf(stderr, "ping: Invalid tclass %s\n", optarg); exit(2); } options |= F_TCLASS; break; case 'I': if (strchr(optarg, ':')) { char *p, *addr = strdup(optarg); if (!addr) { fprintf(stderr, "ping: out of memory\n"); exit(2); } p = strchr(addr, SCOPE_DELIMITER); if (p) { *p = '\0'; device = optarg + (p - addr) + 1; } if (inet_pton(AF_INET6, addr, (char*)&source.sin6_addr) <= 0) { fprintf(stderr, "ping: invalid source address %s\n", optarg); exit(2); } options |= F_STRICTSOURCE; free(addr); } else { device = optarg; } break; case 'M': if (strcmp(optarg, "do") == 0) pmtudisc = IPV6_PMTUDISC_DO; else if (strcmp(optarg, "dont") == 0) pmtudisc = IPV6_PMTUDISC_DONT; else if (strcmp(optarg, "want") == 0) pmtudisc = IPV6_PMTUDISC_WANT; else { fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n"); exit(2); } break; case 'V': printf("ping6 utility, iputils-%s\n", SNAPSHOT); exit(0); case 'N': if (using_ping_socket) { fprintf(stderr, "ping: -N requires raw socket permissions\n"); exit(2); } if (niquery_option_handler(optarg) < 0) { usage(); break; } break; COMMON_OPTIONS common_options(ch); break; default: usage(); } } argc -= optind; argv += optind; #ifdef ENABLE_PING6_RTHDR while (argc > 1) { struct in6_addr *addr; if (srcrt == NULL) { int space; fprintf(stderr, "ping6: Warning: " "Source routing is deprecated by RFC5095.\n"); #ifdef ENABLE_PING6_RTHDR_RFC3542 space = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); #else space = inet6_srcrt_space(IPV6_SRCRT_TYPE_0, argc - 1); #endif if (space == 0) { fprintf(stderr, "srcrt_space failed\n"); exit(2); } #ifdef ENABLE_PING6_RTHDR_RFC3542 if (cmsglen + CMSG_SPACE(space) > sizeof(cmsgbuf)) { fprintf(stderr, "no room for options\n"); exit(2); } #else if (space + cmsglen > sizeof(cmsgbuf)) { fprintf(stderr, "no room for options\n"); exit(2); } #endif srcrt = (struct cmsghdr*)(cmsgbuf+cmsglen); #ifdef ENABLE_PING6_RTHDR_RFC3542 memset(srcrt, 0, CMSG_SPACE(0)); srcrt->cmsg_len = CMSG_LEN(space); srcrt->cmsg_level = IPPROTO_IPV6; srcrt->cmsg_type = IPV6_RTHDR; inet6_rth_init(CMSG_DATA(srcrt), space, IPV6_RTHDR_TYPE_0, argc - 1); cmsglen += CMSG_SPACE(space); #else cmsglen += CMSG_ALIGN(space); inet6_srcrt_init(srcrt, IPV6_SRCRT_TYPE_0); #endif } target = *argv; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; #ifdef USE_IDN hints.ai_flags = AI_IDN; #endif gai = getaddrinfo(target, NULL, &hints, &ai); if (gai) { fprintf(stderr, "unknown host\n"); exit(2); } addr = &((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr; #ifdef ENABLE_PING6_RTHDR_RFC3542 inet6_rth_add(CMSG_DATA(srcrt), addr); #else inet6_srcrt_add(srcrt, addr); #endif if (IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) { memcpy(&firsthop.sin6_addr, addr, 16); #ifdef HAVE_SIN6_SCOPEID firsthop.sin6_scope_id = ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_scope_id; /* Verify scope_id is the same as previous nodes */ if (firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) { fprintf(stderr, "scope discrepancy among the nodes\n"); exit(2); } else if (!scope_id) { scope_id = firsthop.sin6_scope_id; } #endif } freeaddrinfo(ai); argv++; argc--; } #endif if (niquery_is_enabled()) { niquery_init_nonce(); if (!niquery_is_subject_valid()) { ni_subject = &whereto.sin6_addr; ni_subject_len = sizeof(whereto.sin6_addr); ni_subject_type = NI_SUBJ_IPV6; } } if (argc > 1) { #ifndef ENABLE_PING6_RTHDR fprintf(stderr, "ping6: Source routing is deprecated by RFC5095.\n"); #endif usage(); } else if (argc == 1) { target = *argv; } else { if (ni_query < 0 && ni_subject_type != NI_SUBJ_NAME) usage(); target = ni_group; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; #ifdef USE_IDN hints.ai_flags = AI_IDN; #endif gai = getaddrinfo(target, NULL, &hints, &ai); if (gai) { fprintf(stderr, "unknown host\n"); exit(2); } memcpy(&whereto, ai->ai_addr, sizeof(whereto)); whereto.sin6_port = htons(IPPROTO_ICMPV6); if (memchr(target, ':', strlen(target))) options |= F_NUMERIC; freeaddrinfo(ai); if (IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) { memcpy(&firsthop.sin6_addr, &whereto.sin6_addr, 16); #ifdef HAVE_SIN6_SCOPEID firsthop.sin6_scope_id = whereto.sin6_scope_id; /* Verify scope_id is the same as intermediate nodes */ if (firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) { fprintf(stderr, "scope discrepancy among the nodes\n"); exit(2); } else if (!scope_id) { scope_id = firsthop.sin6_scope_id; } #endif } hostname = target; if (IN6_IS_ADDR_UNSPECIFIED(&source.sin6_addr)) { socklen_t alen; int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); if (probe_fd < 0) { perror("socket"); exit(2); } if (device) { #if defined(IPV6_RECVPKTINFO) || defined(HAVE_SIN6_SCOPEID) unsigned int iface = if_name2index(device); #endif #ifdef IPV6_RECVPKTINFO struct in6_pktinfo ipi; memset(&ipi, 0, sizeof(ipi)); ipi.ipi6_ifindex = iface; #endif #ifdef HAVE_SIN6_SCOPEID if (IN6_IS_ADDR_LINKLOCAL(&firsthop.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&firsthop.sin6_addr)) firsthop.sin6_scope_id = iface; #endif enable_capability_raw(); if ( #ifdef IPV6_RECVPKTINFO setsockopt(probe_fd, IPPROTO_IPV6, IPV6_PKTINFO, &ipi, sizeof(ipi)) == -1 && #endif setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) { perror("setsockopt(SO_BINDTODEVICE)"); exit(2); } disable_capability_raw(); } firsthop.sin6_port = htons(1025); if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) { perror("connect"); exit(2); } alen = sizeof(source); if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) { perror("getsockname"); exit(2); } source.sin6_port = 0; close(probe_fd); #ifndef WITHOUT_IFADDRS if (device) { struct ifaddrs *ifa0, *ifa; if (getifaddrs(&ifa0)) { perror("getifaddrs"); exit(2); } for (ifa = ifa0; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6) continue; if (!strncmp(ifa->ifa_name, device, sizeof(device) - 1) && IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, &source.sin6_addr)) break; } if (!ifa) fprintf(stderr, "ping6: Warning: source address might be selected on device other than %s.\n", device); freeifaddrs(ifa0); } #endif } #ifdef HAVE_SIN6_SCOPEID else if (device && (IN6_IS_ADDR_LINKLOCAL(&source.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&source.sin6_addr))) source.sin6_scope_id = if_name2index(device); #endif if (icmp_sock < 0) { errno = socket_errno; perror("ping: icmp open socket"); exit(2); } if (device) { struct cmsghdr *cmsg; struct in6_pktinfo *ipi; cmsg = (struct cmsghdr*)(cmsgbuf+cmsglen); cmsglen += CMSG_SPACE(sizeof(*ipi)); cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); cmsg->cmsg_level = SOL_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; ipi = (struct in6_pktinfo*)CMSG_DATA(cmsg); memset(ipi, 0, sizeof(*ipi)); ipi->ipi6_ifindex = if_name2index(device); } if ((whereto.sin6_addr.s6_addr16[0]&htons(0xff00)) == htons (0xff00)) { if (uid) { if (interval < 1000) { fprintf(stderr, "ping: multicast ping with too short interval.\n"); exit(2); } if (pmtudisc >= 0 && pmtudisc != IPV6_PMTUDISC_DO) { fprintf(stderr, "ping: multicast ping does not fragment.\n"); exit(2); } } if (pmtudisc < 0) pmtudisc = IPV6_PMTUDISC_DO; } if (pmtudisc >= 0) { if (setsockopt(icmp_sock, SOL_IPV6, IPV6_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) { perror("ping: IPV6_MTU_DISCOVER"); exit(2); } } if ((options&F_STRICTSOURCE) && bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) { perror("ping: bind icmp socket"); exit(2); } if (datalen >= sizeof(struct timeval) && (ni_query < 0)) { /* can we time transfer */ timing = 1; } packlen = datalen + 8 + 4096 + 40 + 8; /* 4096 for rthdr */ if (!(packet = (u_char *)malloc((u_int)packlen))) { fprintf(stderr, "ping: out of memory.\n"); exit(2); } working_recverr = 1; hold = 1; if (setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVERR, (char *)&hold, sizeof(hold))) { fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n"); working_recverr = 0; } /* Estimate memory eaten by single packet. It is rough estimate. * Actually, for small datalen's it depends on kernel side a lot. */ hold = datalen+8; hold += ((hold+511)/512)*(40+16+64+160); sock_setbufs(icmp_sock, hold); if (!using_ping_socket) { #ifdef __linux__ csum_offset = 2; sz_opt = sizeof(int); err = setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sz_opt); if (err < 0) { /* checksum should be enabled by default and setting * this option might fail anyway. */ fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed" " - try to continue."); } #endif /* * select icmp echo reply as icmp type to receive */ ICMP6_FILTER_SETBLOCKALL(&filter); if (!working_recverr) { ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter); ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter); ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter); } if (niquery_is_enabled()) ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter); else ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(struct icmp6_filter)); if (err < 0) { perror("setsockopt(ICMP6_FILTER)"); exit(2); } } if (options & F_NOLOOP) { int loop = 0; if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)) == -1) { perror ("can't disable multicast loopback"); exit(2); } } if (options & F_TTL) { if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) { perror ("can't set multicast hop limit"); exit(2); } if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) == -1) { perror ("can't set unicast hop limit"); exit(2); } } if (1) { int on = 1; if ( #ifdef IPV6_RECVHOPLIMIT setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1 && setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_2292HOPLIMIT, &on, sizeof(on)) == -1 #else setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)) == -1 #endif ){ perror ("can't receive hop limit"); exit(2); } } if (options & F_TCLASS) { #ifdef IPV6_TCLASS if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)) == -1) { perror ("setsockopt(IPV6_TCLASS)"); exit(2); } #else fprintf(stderr, "Traffic class is not supported.\n"); #endif } if (options&F_FLOWINFO) { #ifdef IPV6_FLOWINFO_SEND int on = 1; #endif #ifdef IPV6_FLOWLABEL_MGR char freq_buf[CMSG_ALIGN(sizeof(struct in6_flowlabel_req)) + cmsglen]; struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf; int freq_len = sizeof(*freq); #ifdef ENABLE_PING6_RTHDR if (srcrt) freq_len = CMSG_ALIGN(sizeof(*freq)) + srcrt->cmsg_len; #endif memset(freq, 0, sizeof(*freq)); freq->flr_label = htonl(flowlabel & IPV6_FLOWINFO_FLOWLABEL); freq->flr_action = IPV6_FL_A_GET; freq->flr_flags = IPV6_FL_F_CREATE; freq->flr_share = IPV6_FL_S_EXCL; memcpy(&freq->flr_dst, &whereto.sin6_addr, 16); #ifdef ENABLE_PING6_RTHDR if (srcrt) memcpy(freq_buf + CMSG_ALIGN(sizeof(*freq)), srcrt, srcrt->cmsg_len); #endif if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) == -1) { perror ("can't set flowlabel"); exit(2); } flowlabel = freq->flr_label; #ifdef ENABLE_PING6_RTHDR if (srcrt) { cmsglen = (char*)srcrt - (char*)cmsgbuf; srcrt = NULL; } #endif #else fprintf(stderr, "Flow labels are not supported.\n"); exit(2); #endif #ifdef IPV6_FLOWINFO_SEND whereto.sin6_flowinfo = flowlabel; if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &on, sizeof(on)) == -1) { perror ("can't send flowinfo"); exit(2); } #else fprintf(stderr, "Flowinfo is not supported.\n"); exit(2); #endif } printf("PING %s(%s) ", hostname, pr_addr(&whereto.sin6_addr)); if (flowlabel) printf(", flow 0x%05x, ", (unsigned)ntohl(flowlabel)); if (device || (options&F_STRICTSOURCE)) { printf("from %s %s: ", pr_addr_n(&source.sin6_addr), device ? : ""); }
static int ipv6ns_open(void) { int on; int len; struct icmp6_filter filt; #ifdef IPV6_SEND_DAD union { struct sockaddr sa; struct sockaddr_in6 sin; } su; #endif if (sock != -1) return sock; sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock == -1) return -1; on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) == -1) goto eexit; on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1) goto eexit; ICMP6_FILTER_SETBLOCKALL(&filt); #ifdef IPV6_SEND_DAD /* We send DAD requests from the unspecified address. */ unspec_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (unspec_sock == -1) goto eexit; if (setsockopt(unspec_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) goto eexit; memset(&su, 0, sizeof(su)); su.sin.sin6_family = AF_INET6; #ifdef SIN6_LEN su.sin.sin6_len = sizeof(su.sin); #endif if (bind(unspec_sock, &su.sa, sizeof(su.sin)) == -1) goto eexit; #endif ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt); if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) goto eexit; set_cloexec(sock); #if DEBUG_MEMORY atexit(ipv6ns_cleanup); #endif #ifdef LISTEN_DAD syslog(LOG_WARNING, "kernel does not report DAD results to userland"); syslog(LOG_WARNING, "warning listening to duplicated addresses on the wire"); #endif len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); sndbuf = calloc(1, len); if (sndbuf == NULL) goto eexit; sndhdr.msg_namelen = sizeof(struct sockaddr_in6); sndhdr.msg_iov = sndiov; sndhdr.msg_iovlen = 1; sndhdr.msg_control = sndbuf; sndhdr.msg_controllen = len; rcvbuf = calloc(1, len); if (rcvbuf == NULL) goto eexit; rcvhdr.msg_name = &from; rcvhdr.msg_namelen = sizeof(from); rcvhdr.msg_iov = rcviov; rcvhdr.msg_iovlen = 1; rcvhdr.msg_control = rcvbuf; rcvhdr.msg_controllen = len; rcviov[0].iov_base = ansbuf; rcviov[0].iov_len = sizeof(ansbuf); eloop_event_add(sock, ipv6ns_handledata, NULL); return sock; eexit: syslog(LOG_ERR, "%s: %m", __func__); close(sock); sock = -1; free(sndbuf); sndbuf = NULL; free(rcvbuf); rcvbuf = NULL; return -1; }
static void ping(const char *host) { char packet[datalen + MAXIPLEN + MAXICMPLEN]; char buf[INET6_ADDRSTRLEN]; int sockopt; struct msghdr msg; struct sockaddr_in6 from; struct iovec iov; char control_buf[CMSG_SPACE(36)]; pingsock = create_icmp6_socket(); memset(&pingaddr, 0, sizeof(struct sockaddr_in)); pingaddr.sin6_family = AF_INET6; hostent = xgethostbyname2(host, AF_INET6); if (hostent->h_addrtype != AF_INET6) bb_error_msg_and_die("unknown address type; only AF_INET6 is currently supported."); memcpy(&pingaddr.sin6_addr, hostent->h_addr, sizeof(pingaddr.sin6_addr)); #ifdef ICMP6_FILTER { struct icmp6_filter filt; if (!(options & O_VERBOSE)) { ICMP6_FILTER_SETBLOCKALL(&filt); #if 0 if ((options & F_FQDN) || (options & F_FQDNOLD) || (options & F_NODEADDR) || (options & F_SUPTYPES)) ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); else #endif ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); } else { ICMP6_FILTER_SETPASSALL(&filt); } if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) bb_error_msg_and_die("setsockopt(ICMP6_FILTER)"); } #endif /*ICMP6_FILTER*/ /* enable broadcast pings */ sockopt = 1; setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, sizeof(sockopt)); /* set recv buf for broadcast pings */ sockopt = 48 * 1024; setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt)); sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt, sizeof(sockopt)); sockopt = 1; setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *) &sockopt, sizeof(sockopt)); if (ifname) { if ((pingaddr.sin6_scope_id = if_nametoindex(ifname)) == 0) bb_error_msg_and_die("%s: invalid interface name", ifname); } printf("PING %s (%s): %d data bytes\n", hostent->h_name, inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr, buf, sizeof(buf)), datalen); signal(SIGINT, pingstats); /* start the ping's going ... */ sendping(0); /* listen for replies */ msg.msg_name=&from; msg.msg_namelen=sizeof(from); msg.msg_iov=&iov; msg.msg_iovlen=1; msg.msg_control=control_buf; iov.iov_base=packet; iov.iov_len=sizeof(packet); while (1) { int c; struct cmsghdr *cmsgptr = NULL; int hoplimit=-1; msg.msg_controllen=sizeof(control_buf); if ((c = recvmsg(pingsock, &msg, 0)) < 0) { if (errno == EINTR) continue; bb_perror_msg("recvfrom"); continue; } for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == SOL_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT ) { hoplimit=*(int*)CMSG_DATA(cmsgptr); } } unpack(packet, c, &from, hoplimit); if (pingcount > 0 && nreceived >= pingcount) break; } pingstats(0); }
int sockopen(void) { static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL; int sndcmsglen, on; static u_char answer[1500]; struct icmp6_filter filt; sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { warnmsg(LOG_ERR, __func__, "malloc for receive msghdr failed"); return (-1); } if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) { warnmsg(LOG_ERR, __func__, "malloc for send msghdr failed"); return (-1); } if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); return (-1); } /* specify to tell receiving interface */ on = 1; if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) { warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s", strerror(errno)); exit(1); } /* specify to tell value of hoplimit field of received IP6 hdr */ on = 1; if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) { warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s", strerror(errno)); exit(1); } /* specfiy to accept only router advertisements on the socket */ ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) { warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s", strerror(errno)); return(-1); } /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)answer; rcviov[0].iov_len = sizeof(answer); rcvmhdr.msg_name = (caddr_t)&from; rcvmhdr.msg_iov = rcviov; rcvmhdr.msg_iovlen = 1; rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; /* initialize msghdr for sending packets */ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); sndmhdr.msg_iov = sndiov; sndmhdr.msg_iovlen = 1; sndmhdr.msg_control = (caddr_t)sndcmsgbuf; sndmhdr.msg_controllen = sndcmsglen; return (rssock); }
int main(int argc, char *argv[]) { int i; struct icmp6_filter filt; u_int hlim = 1; fd_set fdset; struct itimerval itimer; u_int type; int ch; type = MLD6_LISTENER_QUERY; while ((ch = getopt(argc, argv, "dr")) != -1) { switch (ch) { case 'd': type = MLD6_LISTENER_DONE; break; case 'r': type = MLD6_LISTENER_REPORT; break; default: usage(); /*NOTREACHED*/ } } argv += optind; argc -= optind; if (argc != 1 && argc != 2) usage(); ifindex = (u_short)if_nametoindex(argv[0]); if (ifindex == 0) usage(); if (argc == 2 && inet_pton(AF_INET6, argv[1], &maddr) != 1) usage(); if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) err(1, "socket"); if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim, sizeof(hlim)) == -1) err(1, "setsockopt(IPV6_MULTICAST_HOPS)"); mreq.ipv6mr_multiaddr = any; mreq.ipv6mr_interface = ifindex; if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) err(1, "setsockopt(IPV6_JOIN_GROUP)"); ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_QUERY, &filt); ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REPORT, &filt); ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REDUCTION, &filt); if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) err(1, "setsockopt(ICMP6_FILTER)"); make_msg(ifindex, &maddr, type); if (sendmsg(s, &m, 0) < 0) err(1, "sendmsg"); itimer.it_value.tv_sec = QUERY_RESPONSE_INTERVAL / 1000; itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = 0; itimer.it_value.tv_usec = 0; signal(SIGALRM, quit); setitimer(ITIMER_REAL, &itimer, NULL); FD_ZERO(&fdset); for (;;) { FD_SET(s, &fdset); if ((i = select(s + 1, &fdset, NULL, NULL, NULL)) < 0) perror("select"); if (i == 0) continue; else dump(s); } }
void traceloop(void) { int seq, code, done; double rtt; struct rec *rec; struct timeval tvrecv; recvfd = socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto); setuid(getuid()); /* don't need special permissions anymore */ #ifdef IPV6 if (pr->sasend->sa_family == AF_INET6 && verbose == 0) { struct icmp6_filter myfilt; ICMP6_FILTER_SETBLOCKALL(&myfilt); ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &myfilt); ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &myfilt); setsockopt(recvfd, IPPROTO_IPV6, ICMP6_FILTER, &myfilt, sizeof(myfilt)); } #endif sendfd = socket(pr->sasend->sa_family, SOCK_DGRAM, 0); pr->sabind->sa_family = pr->sasend->sa_family; sport = (getpid() & 0xffff) | 0x8000; /* our source UDP port # */ sock_set_port(pr->sabind, pr->salen, htons(sport)); bind(sendfd, pr->sabind, pr->salen); sig_alrm(SIGALRM); seq = 0; done = 0; for (ttl = 1; ttl <= max_ttl && done == 0; ttl++) { setsockopt(sendfd, pr->ttllevel, pr->ttloptname, &ttl, sizeof(int)); bzero(pr->salast, pr->salen); printf("%2d ", ttl); fflush(stdout); for (probe = 0; probe < nprobes; probe++) { rec = (struct rec *) sendbuf; rec->rec_seq = ++seq; rec->rec_ttl = ttl; gettimeofday(&rec->rec_tv, NULL); sock_set_port(pr->sasend, pr->salen, htons(dport + seq)); sendto(sendfd, sendbuf, datalen, 0, pr->sasend, pr->salen); if ( (code = (*pr->recv)(seq, &tvrecv)) == -3) printf(" *"); /* timeout, no reply */ else { char str[NI_MAXHOST]; if (sock_cmp_addr(pr->sarecv, pr->salast, pr->salen) != 0) { if (getnameinfo(pr->sarecv, pr->salen, str, sizeof(str), NULL, 0, 0) == 0) printf(" %s (%s)", str, sock_ntop_host(pr->sarecv, pr->salen, ipstr, sizeof(ipstr))); else printf(" %s", sock_ntop_host(pr->sarecv, pr->salen, ipstr, sizeof(ipstr))); memcpy(pr->salast, pr->sarecv, pr->salen); } tv_sub(&tvrecv, &rec->rec_tv); rtt = tvrecv.tv_sec * 1000.0 + tvrecv.tv_usec / 1000.0; printf(" %.3f ms", rtt); if (code == -1) /* port unreachable; at destination */ done++; else if (code >= 0) printf(" (ICMP %s)", (*pr->icmpcode)(code)); } fflush(stdout); } printf("\n"); } }
/** * Entry point. */ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp) { int rc; LogFlowFuncEnter(); NOREF(envp); #ifdef RT_OS_WINDOWS WSADATA wsaData; int err; err = WSAStartup(MAKEWORD(2,2), &wsaData); if (err) { fprintf(stderr, "wsastartup: failed (%d)\n", err); return 1; } #endif SOCKET icmpsock4 = INVALID_SOCKET; SOCKET icmpsock6 = INVALID_SOCKET; #ifndef RT_OS_DARWIN const int icmpstype = SOCK_RAW; #else /* on OS X it's not privileged */ const int icmpstype = SOCK_DGRAM; #endif icmpsock4 = socket(AF_INET, icmpstype, IPPROTO_ICMP); if (icmpsock4 == INVALID_SOCKET) { perror("IPPROTO_ICMP"); #ifdef VBOX_RAWSOCK_DEBUG_HELPER icmpsock4 = getrawsock(AF_INET); #endif } if (icmpsock4 != INVALID_SOCKET) { #ifdef ICMP_FILTER // Linux specific struct icmp_filter flt = { ~(uint32_t)( (1U << ICMP_ECHOREPLY) | (1U << ICMP_DEST_UNREACH) | (1U << ICMP_TIME_EXCEEDED) ) }; int status = setsockopt(icmpsock4, SOL_RAW, ICMP_FILTER, &flt, sizeof(flt)); if (status < 0) { perror("ICMP_FILTER"); } #endif } icmpsock6 = socket(AF_INET6, icmpstype, IPPROTO_ICMPV6); if (icmpsock6 == INVALID_SOCKET) { perror("IPPROTO_ICMPV6"); #ifdef VBOX_RAWSOCK_DEBUG_HELPER icmpsock6 = getrawsock(AF_INET6); #endif } if (icmpsock6 != INVALID_SOCKET) { #ifdef ICMP6_FILTER // Windows doesn't support RFC 3542 API /* * XXX: We do this here for now, not in pxping.c, to avoid * name clashes between lwIP and system headers. */ struct icmp6_filter flt; ICMP6_FILTER_SETBLOCKALL(&flt); ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &flt); ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &flt); ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &flt); ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &flt); ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &flt); int status = setsockopt(icmpsock6, IPPROTO_ICMPV6, ICMP6_FILTER, &flt, sizeof(flt)); if (status < 0) { perror("ICMP6_FILTER"); } #endif } HRESULT hrc = com::Initialize(); if (FAILED(hrc)) { #ifdef VBOX_WITH_XPCOM if (hrc == NS_ERROR_FILE_ACCESS_DENIED) { char szHome[RTPATH_MAX] = ""; int vrc = com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome), false); if (RT_SUCCESS(vrc)) { return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM: %s: %Rhrf", szHome, hrc); } } #endif // VBOX_WITH_XPCOM return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM: %Rhrf", hrc); } rc = vboxNetNATLogInit(argc, argv); // shall we bail if we failed to init logging? g_pLwipNat = new VBoxNetLwipNAT(icmpsock4, icmpsock6); Log2(("NAT: initialization\n")); rc = g_pLwipNat->parseArgs(argc - 1, argv + 1); rc = (rc == 0) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /* XXX: FIXME */ if (RT_SUCCESS(rc)) rc = g_pLwipNat->init(); if (RT_SUCCESS(rc)) g_pLwipNat->run(); delete g_pLwipNat; return 0; }
static PING * ping_init (int type, int ident) { int fd, err; const int on = 1; PING *p; struct icmp6_filter filter; /* Initialize raw ICMPv6 socket */ fd = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd < 0) { if (errno == EPERM) error (EXIT_FAILURE, errno, NULL); return NULL; } /* Tell which ICMPs we are interested in. */ ICMP6_FILTER_SETBLOCKALL (&filter); ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &filter); ICMP6_FILTER_SETPASS (ICMP6_DST_UNREACH, &filter); ICMP6_FILTER_SETPASS (ICMP6_PACKET_TOO_BIG, &filter); ICMP6_FILTER_SETPASS (ICMP6_TIME_EXCEEDED, &filter); ICMP6_FILTER_SETPASS (ICMP6_PARAM_PROB, &filter); err = setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter)); if (err) { close (fd); return NULL; } err = setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof (on)); if (err) { close (fd); return NULL; } /* Allocate PING structure and initialize it to default values */ p = malloc (sizeof (*p)); if (!p) { close (fd); return NULL; } memset (p, 0, sizeof (*p)); p->ping_fd = fd; p->ping_count = DEFAULT_PING_COUNT; p->ping_interval = PING_DEFAULT_INTERVAL; p->ping_datalen = sizeof (struct icmp6_hdr); /* Make sure we use only 16 bits in this field, id for icmp is a u_short. */ p->ping_ident = ident & 0xFFFF; p->ping_cktab_size = PING_CKTABSIZE; gettimeofday (&p->ping_start_time, NULL); return p; }
STATUS init_mproxy6(mcast_proxy *p_mp) { struct icmp6_filter filt; int on; #ifdef ENABLE_IMP_MLD if (p_mp->mld_version != IM_DISABLE) { struct in6_addr all_ipv6_router; imp_interface* p_if = NULL; p_mp->mld_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if(p_mp->mld_socket == -1) { IMP_LOG_ERROR("can't create mld socket\n"); return STATUS_NOK; } /* filter all non-MLD ICMP messages */ ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(MLD_LISTENER_REPORT, &filt); ICMP6_FILTER_SETPASS(MLD_LISTENER_REDUCTION, &filt); ICMP6_FILTER_SETPASS(MLD_V2_LISTENER_REPORT, &filt); if (setsockopt(p_mp->mld_socket, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) IMP_LOG_ERROR("ICMP6_FILTER: %s\n", strerror(errno)); /* specify to tell receiving interface */ on = 1; if (setsockopt(p_mp->mld_socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) IMP_LOG_ERROR("IPV6_RECVPKTINFO: %s\n", strerror(errno)); on = 1; if (setsockopt(p_mp->mld_socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) IMP_LOG_ERROR("IPV6_MULTICAST_HOPS: %s\n", strerror(errno)); on = 0; if (setsockopt(p_mp->mld_socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on)) < 0) IMP_LOG_ERROR("IPV6_MULTICAST_LOOP: %s\n", strerror(errno)); on = 1; if (setsockopt(p_mp->mld_socket, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &on, sizeof(on)) < 0) IMP_LOG_ERROR("IPV6_RECVHOPOPTS: %s\n", strerror(errno)); if (k_start6_mproxy(p_mp->mld_socket) < 0 ) return STATUS_NOK; IMP_LOG_DEBUG("p_mp->mld_socket = %d\n", p_mp->mld_socket); p_mp->mld_udp_socket = socket(AF_INET6, SOCK_DGRAM, 0); if(p_mp->mld_udp_socket == -1) { IMP_LOG_ERROR("can't create mld udp socket\n"); return STATUS_NOK; } for(p_if = imp_interface_first(); p_if; p_if = LIST_NEXT(p_if, link)){ if(p_if->if_addr.ss.ss_family != AF_INET6 || p_if->type != INTERFACE_DOWNSTREAM) continue; if(inet_pton(AF_INET6, "FF02::2", &all_ipv6_router) == 1) { pi_addr pir; imp_build_piaddr(AF_INET6, &all_ipv6_router, &pir); if(k_mcast_join(&pir, p_if->if_name) < 0) IMP_LOG_DEBUG("k_mcast_join: %s\n", strerror(errno)); } if(inet_pton(AF_INET6, "FF02::16", &all_ipv6_router) == 1) { pi_addr pir; imp_build_piaddr(AF_INET6, &all_ipv6_router, &pir); if(k_mcast_join(&pir, p_if->if_name) < 0) IMP_LOG_DEBUG("k_mcast_join: %s\n", strerror(errno)); } } } #endif return STATUS_OK; }
/******************************************************************************* 函数名称 : healthy_check_ipping_init 功能描述 : ping 检测启动函数 输入参数 : hc_ping_s *ping_cfg: 当前ip 配置结构 输出参数 : 无 返回值 : ERROR_SUCCESS 处理成功 HC_ERR_SOCKET_INIT_FAIL socket 建立失败 HC_ERR_SET_SOCK_OPT_FAIL 设置socket 选项失败 -------------------------------------------------------------------------------- 最近一次修改记录 : 修改作者 : 王宗发 修改目的 : 新增函数 修改日期 : 20101020 ********************************************************************************/ s32 healthy_check_ipping_init(hc_ping_s *ping_cfg) { s32 fd; s32 val = 1; s32 var = 0; s32 err_tmp = ERROR_SUCCESS; struct ifreq ifreq; struct icmp6_filter filter; fd = socket (AF_INET6, SOCK_RAW, g_hc_ping_checker.proto); if (fd < 0) { ping_cfg->ping_check_flag = HC_ERR_SOCKET_INIT_FAIL; if (errno == EPERM) { printf("ping: ping must run as root\n"); } return !ERROR_SUCCESS; } ping_cfg->fd = fd; var = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, O_NONBLOCK | var); ICMP6_FILTER_SETBLOCKALL (&filter); ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &filter); err_tmp = setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter)); if(ERROR_SUCCESS != err_tmp) { close (fd); ping_cfg->ping_check_flag = HC_ERR_SET_SOCK_OPT_FAIL; return err_tmp; } /* err_tmp = setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, (char *)&val, sizeof(val)); if(ERROR_SUCCESS != err_tmp) { close (fd); ping_cfg->ping_check_flag = HC_ERR_SET_SOCK_OPT_FAIL; return err_tmp; } */ err_tmp = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)); if(ERROR_SUCCESS != err_tmp) { close(fd); ping_cfg->ping_check_flag = HC_ERR_SET_SOCK_OPT_FAIL; return err_tmp; } /*检查是否指定接口*/ if('\0' != *(ping_cfg->if_name)) { memset(&ifreq, 0, sizeof(ifreq)); strncpy((char *)&ifreq.ifr_name, (s8 *)(ping_cfg->if_name), sizeof (ifreq.ifr_name)); err_tmp = setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof (ifreq)); if(ERROR_SUCCESS != err_tmp) { close(fd); ping_cfg->ping_check_flag = HC_ERR_SET_SOCK_OPT_FAIL; return err_tmp; } } /*入参中有端口参数时,设置tos字段,走策略路由 */ /* if(0 != ping_cfg->tos) { err_tmp = setsockopt(ping_cfg->fd, IPPROTO_IPV6, IP_TOS, (const char *)&(ping_cfg->tos), sizeof(ping_cfg->tos)); if(ERROR_SUCCESS != err_tmp) { close(fd); ping_cfg->ping_check_flag = HC_ERR_SET_SOCK_OPT_FAIL; return err_tmp; } } */ return err_tmp; }
static void sock6_open(struct flags *flags #ifdef IPSEC_POLICY_IPSEC , char *policy #endif /* IPSEC_POLICY_IPSEC */ ) { struct icmp6_filter filt; int on; #ifdef IPSEC #ifndef IPSEC_POLICY_IPSEC int optval; #endif #endif if (with_v6dest == 0) return; if (with_v6dest && (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { syslog(LOG_ERR, "<%s> socket(v6): %s", __func__, strerror(errno)); exit(1); } /* * join all routers multicast addresses. */ #if 0 /* XXX: not necessary ?? */ join_multi(LL_ALLROUTERS); join_multi(SL_ALLROUTERS); #endif /* set icmpv6 filter */ ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", __func__, strerror(errno)); exit(1); } /* specify to tell receiving interface */ on = 1; if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__, strerror(errno)); exit(1); } #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC if (flags->policy) { char *buf; buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); /* XXX should handle in/out bound policy. */ if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) err(1, "setsockopt(IPV6_IPSEC_POLICY)"); free(buf); } #else /* IPSEC_POLICY_IPSEC */ if (flags->auth) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &optval, sizeof(optval)) == -1) { syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", __func__, strerror(errno)); exit(1); } } if (flags->encrypt) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &optval, sizeof(optval)) == -1) { syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", __func__, strerror(errno)); exit(1); } } #endif /* IPSEC_POLICY_IPSEC */ #endif /* IPSEC */ return; }
void block() { ICMP6_FILTER_SETBLOCKALL(&_filter); }
int open_icmpv6_socket(void) { int sock; struct icmp6_filter filter; int err, val; sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock < 0) { flog(LOG_ERR, "can't create socket(AF_INET6): %s", strerror(errno)); return -1; } val = 1; err = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); if (err < 0) { flog(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO): %s", strerror(errno)); return -1; } val = 2; #ifdef __linux__ err = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)); #else err = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val)); #endif if (err < 0) { flog(LOG_ERR, "setsockopt(IPV6_CHECKSUM): %s", strerror(errno)); return -1; } val = 255; err = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)); if (err < 0) { flog(LOG_ERR, "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno)); return -1; } val = 255; err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)); if (err < 0) { flog(LOG_ERR, "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno)); return -1; } #ifdef IPV6_RECVHOPLIMIT val = 1; err = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)); if (err < 0) { flog(LOG_ERR, "setsockopt(IPV6_RECVHOPLIMIT): %s", strerror(errno)); return -1; } #endif /* * setup ICMP filter */ ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); err = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)); if (err < 0) { flog(LOG_ERR, "setsockopt(ICMPV6_FILTER): %s", strerror(errno)); return -1; } return sock; }
static void ping(const char *host) { char packet[datalen + MAXIPLEN + MAXICMPLEN]; char buf[INET6_ADDRSTRLEN]; int sockopt; struct msghdr msg; struct sockaddr_in6 from; struct iovec iov; char control_buf[CMSG_SPACE(36)]; pingsock = create_icmp6_socket(); memset(&pingaddr, 0, sizeof(struct sockaddr_in)); pingaddr.sin6_family = AF_INET6; hostent = xgethostbyname2(host, AF_INET6); if (hostent->h_addrtype != AF_INET6) bb_error_msg_and_die("unknown address type; only AF_INET6 is currently supported"); memcpy(&pingaddr.sin6_addr, hostent->h_addr, sizeof(pingaddr.sin6_addr)); #ifdef ICMP6_FILTER { struct icmp6_filter filt; if (!(option_mask32 & OPT_VERBOSE)) { ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); } else { ICMP6_FILTER_SETPASSALL(&filt); } if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) bb_error_msg_and_die("setsockopt(ICMP6_FILTER)"); } #endif /*ICMP6_FILTER*/ /* enable broadcast pings */ setsockopt_broadcast(pingsock); /* set recv buf for broadcast pings */ sockopt = 48 * 1024; /* explain why 48k? */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt)); sockopt = 2; /* iputils-ss020927 does this */ sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt, sizeof(sockopt)); /* request ttl info to be returned in ancillary data */ sockopt = 1; setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *) &sockopt, sizeof(sockopt)); if (if_index) pingaddr.sin6_scope_id = if_index; printf("PING %s (%s): %d data bytes\n", hostent->h_name, inet_ntop(AF_INET6, &pingaddr.sin6_addr, buf, sizeof(buf)), datalen); signal(SIGINT, pingstats); /* start the ping's going ... */ sendping(0); /* listen for replies */ msg.msg_name = &from; msg.msg_namelen = sizeof(from); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = control_buf; iov.iov_base = packet; iov.iov_len = sizeof(packet); while (1) { int c; struct cmsghdr *mp; int hoplimit = -1; msg.msg_controllen = sizeof(control_buf); c = recvmsg(pingsock, &msg, 0); if (c < 0) { if (errno != EINTR) bb_perror_msg("recvfrom"); continue; } for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) { if (mp->cmsg_level == SOL_IPV6 && mp->cmsg_type == IPV6_HOPLIMIT /* don't check len - we trust the kernel: */ /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */ ) { hoplimit = *(int*)CMSG_DATA(mp); } } unpack(packet, c, &from, hoplimit); if (pingcount > 0 && nreceived >= pingcount) break; } pingstats(0); }