From 60592283d31a883c3b3c30fa54f88e2ea814b621 Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 15 Jun 2026 15:14:07 +0000 Subject: [PATCH] Use libnetutil's IPv6 sending for Nping --- nping/NpingOps.cc | 11 --- nping/NpingOps.h | 1 - nping/ProbeMode.cc | 176 +++++++-------------------------------------- nping/ProbeMode.h | 1 - nping/utils_net.cc | 88 ++--------------------- 5 files changed, 30 insertions(+), 247 deletions(-) diff --git a/nping/NpingOps.cc b/nping/NpingOps.cc index a18d0815f..c9d79982e 100644 --- a/nping/NpingOps.cc +++ b/nping/NpingOps.cc @@ -848,17 +848,6 @@ bool NpingOps::ipv6(){ } /* End of ipv6() */ -/* Returns true if we are sending IPv6 packets at raw TCP level (using a - * useless and boring IPv6 socket that doesn't let us include our own IPv6 - * header)*/ -bool NpingOps::ipv6UsingSocket(){ - if( this->getIPVersion() == IP_VERSION_6 && this->sendEth()==false) - return true; - else - return false; -} /* End of ipv6UsingSocket() */ - - /* Returns AF_INET or AF_INET6, depending on current configuration */ int NpingOps::af(){ if( this->getIPVersion() == IP_VERSION_6 ) diff --git a/nping/NpingOps.h b/nping/NpingOps.h index 65c3063e6..c9e57f5ab 100644 --- a/nping/NpingOps.h +++ b/nping/NpingOps.h @@ -372,7 +372,6 @@ class NpingOps { bool issetIPVersion(); bool ipv4(); bool ipv6(); - bool ipv6UsingSocket(); int af(); /* Privileges */ diff --git a/nping/ProbeMode.cc b/nping/ProbeMode.cc index 15232734c..f7921949d 100644 --- a/nping/ProbeMode.cc +++ b/nping/ProbeMode.cc @@ -304,13 +304,8 @@ int ProbeMode::start(){ if( o.getMode()!=ARP && o.sendEth()==false ){ /* Get socket descriptor. No need for it in ARP since we send at eth level */ - if ((rawipsd = obtainRawSocket()) < 0 ) + if ((rawipsd = netutil_raw_socket(o.issetDevice() ? o.getDevice() : NULL)) < 0 ) nping_fatal(QT_3,"Couldn't acquire raw socket. Are you root?"); - if ( o.issetDevice() ) { - if (!socket_bindtodevice(rawipsd, o.getDevice()) && errno != EPERM) { - nping_warning(QT_2, "Error binding socket to device %s", o.getDevice() ); - } - } } /* Check if we have enough information to get the party started */ @@ -675,75 +670,9 @@ int ProbeMode::createIPv6(IPv6Header *i, PacketElement *next_element, const char } /* End of createIPv6() */ -/** This function is a bit tricky. The thing is that some engineer had - * the brilliant idea to remove IP_HDRINCL support in IPv6. As a result, it's - * a big pain in the ass to create raw IPv6 headers because we can only do it - * if we are sending packets at raw Ethernet level. So if we want our own IPv6 - * header (for source IP spoofing, etc) we have to do things like determine - * source and dest MAC addresses (this is even more complicated in IPv6 than - * in IPv4 because we don't have ARP anymore, we have to use something new, the - * NDP, Neighbor Discovery Protocol.) - * So the thing is that, if the user does not want to play with the IPv6 header, - * why bother with all that link layer work? So what we do is create raw - * transport layer packets and then send them through a raw IPv6 socket. The - * socket will encapsulate our packets into a nice clean IPv6 header - * automatically so we don't have to worry about low level details anymore. - * - * So this function basically takes a raw IPv6 socket descriptor and then tries - * to set some basic parameters (like Hop Limit) using setsockopt() calls. - * It always returns OP_SUCCESS. However, if errors are found, they are printed - * (QT_2 level) using nping_warning(); - * */ -int ProbeMode::doIPv6ThroughSocket(int rawfd){ - - /* Hop Limit */ - int hoplimit=0; - if( o.issetHopLimit() ) - hoplimit= o.getHopLimit(); - else if ( o.issetTraceroute() ){ - hoplimit= (o.getCurrentRound()<255)? o.getCurrentRound() : (o.getCurrentRound()%255)+1; - }else{ - hoplimit=DEFAULT_IPv6_TTL; - } - if( setsockopt(rawfd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&hoplimit, sizeof(hoplimit)) != 0 ) - nping_warning(QT_2, "doIPv6ThroughSocket(): setsockopt() for Unicast Hop Limit on IPv6 socket failed"); - if( setsockopt(rawfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hoplimit, sizeof(hoplimit)) != 0 ) - nping_warning(QT_2, "doIPv6ThroughSocket(): setsockopt() for Multicast Hop Limit on IPv6 socket failed"); - -#ifdef IPV6_CHECKSUM /* This is not available in when compiling with MinGW */ - /* Transport layer checksum */ - /* This is totally crazy. We have to tell the kernel EXPLICITLY that we - * want it to set the TCP/UDP checksum for us. Why the hell is this the - * default behavior if it's so incredibly difficult to get the IPv6 source - * address? - * Additionally, we have to be very careful not to set this option when - * dealing with ICMPv6 because in that case the kernel computes the - * checksum automatically and Nping can actually crash if we've set - * this option manually, can you believe it? */ - if( o.getMode()==TCP || o.getMode()==UDP){ - /* We don't request valid TCP checksums if the user requested bogus sums */ - if( o.getBadsum()==false ){ - int offset = 16; - if( setsockopt (rawfd, IPPROTO_IPV6, IPV6_CHECKSUM, (char *)&offset, sizeof(offset)) != 0 ) - nping_warning(QT_2, "doIPv6ThroughSocket(): failed to set IPV6_CHECKSUM option on IPv6 socket. "); - } - } -#endif - - return OP_SUCCESS; - -} /* End of doIPv6ThroughSocket() */ - - - - - /** This function handles TCP packet creation. However, the final packet that * it produces also includes an IP header. - * There is one exception. When we are sending IPv6 packet at raw TCP level, - * the returned packet does not contain an IPv6 header but the supplied - * rawfd socket descriptor is ready to go because some options have been - * set on it by doIPv6ThroughSocket(). */ + */ int ProbeMode::fillPacketTCP(NpingTarget *target, u16 port, u8 *buff, int bufflen, int *filledlen, int rawfd){ IPv4Header i; @@ -813,47 +742,19 @@ int ProbeMode::fillPacketTCP(NpingTarget *target, u16 port, u8 *buff, int buffle break; case IP_VERSION_6: - if( o.sendEth() ){ - /* Fill the IPv6Header object with the info from NpingOps */ - createIPv6(&i6, &t, "TCP", target); + /* Fill the IPv6Header object with the info from NpingOps */ + createIPv6(&i6, &t, "TCP", target); - if( o.getBadsum() == true ) - t.setSumRandom(); - else{ - *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); - ip6_checksum(buff, *filledlen); /* Provided by dnet */ - return OP_SUCCESS; - } - - /* Store result in user supplied buffer */ + if( o.getBadsum() == true ) + t.setSumRandom(); + else{ *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); - }else{ - doIPv6ThroughSocket(rawfd); - - /* Set some bogus checksum */ - if( o.getBadsum()==true ) - t.setSumRandom(); - /* Set checksum to zero and pray for the kernel to set it to - * the right value. Brothers and sisters: - * - * Our TCP/IP stack, Who is in the kernel, - * Holy is Your Name; - * Your kingdom come, - * Your will be done, - * on userland as it is in kernel space. - * Give us this day our TCP checksum, - * and forgive us for our raw sockets, - * as we forgive you for your kernel panics; - * and lead us not into /dev/null, - * but deliver our packet to the next hop. Amen. - * */ - else - t.setSum(0); - - /* Since we cannot include our own header like we do in IPv4, the - * buffer we return is the TCP one. */ - *filledlen = t.dumpToBinaryBuffer(buff, bufflen); + ip6_checksum(buff, *filledlen); /* Provided by dnet */ + return OP_SUCCESS; } + + /* Store result in user supplied buffer */ + *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); break; default: @@ -873,10 +774,7 @@ int ProbeMode::fillPacketTCP(NpingTarget *target, u16 port, u8 *buff, int buffle /** This function handles UDP packet creation. However, the final packet that * it produces also includes an IP header. - * There is one exception. When we are sending IPv6 packet at raw TCP level, - * the returned packet does not contain an IPv6 header but the supplied - * rawfd socket descriptor is ready to go because some options have been - * set on it by doIPv6ThroughSocket(). */ + */ int ProbeMode::fillPacketUDP(NpingTarget *target, u16 port, u8 *buff, int bufflen, int *filledlen, int rawfd){ IPv4Header i; @@ -932,36 +830,18 @@ int ProbeMode::fillPacketUDP(NpingTarget *target, u16 port, u8 *buff, int buffle break; case IP_VERSION_6: + /* Fill the IPv6Header object with the info from NpingOps */ + createIPv6(&i6, &u, "UDP", target); - if( o.sendEth() ){ - /* Fill the IPv6Header object with the info from NpingOps */ - createIPv6(&i6, &u, "UDP", target); - - if( o.getBadsum() == true ){ - u.setSumRandom(); - /* Store result in user supplied buffer */ - *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); - } - else{ - *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); - ip6_checksum(buff, *filledlen); /* Provided by dnet */ - return OP_SUCCESS; - } - }else{ - doIPv6ThroughSocket(rawfd); - - /* Set some bogus checksum */ - if( o.getBadsum()==true ) - u.setSumRandom(); - /* Set checksum to zero and assume the kernel is gonna set the - * right value. If it doesn't, it's not that important since - * UDP checksum is optional and can safely be set to zero */ - else - u.setSum(0); - - /* Since we cannot include our own header like we do in IPv4, the - * buffer we return is the UDP one. */ - *filledlen = u.dumpToBinaryBuffer(buff, bufflen); + if( o.getBadsum() == true ){ + u.setSumRandom(); + /* Store result in user supplied buffer */ + *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); + } + else{ + *filledlen = i6.dumpToBinaryBuffer(buff, bufflen); + ip6_checksum(buff, *filledlen); /* Provided by dnet */ + return OP_SUCCESS; } break; @@ -1599,14 +1479,6 @@ void ProbeMode::probe_nping_event_handler(nsock_pool nsp, nsock_event nse, void if( mypacket->type==PKT_TYPE_ARP_RAW ) getPacketStrInfo("ARP",mypacket->pkt+14, mypacket->pktLen-14, pktinfobuffer, 512); - else if ( o.ipv6UsingSocket() ){ - size_t sslen; - struct sockaddr_storage ss_src; - struct sockaddr_storage ss_dst; - mypacket->target->getSourceSockAddr(&ss_src, &sslen); - mypacket->target->getTargetSockAddr(&ss_dst, &sslen); - getPacketStrInfo("IPv6_NO_HEADER", mypacket->pkt, mypacket->pktLen, pktinfobuffer, 512, &ss_src, &ss_dst ); - } else getPacketStrInfo("IP", mypacket->pkt+link_offset, mypacket->pktLen-link_offset, pktinfobuffer, 512); diff --git a/nping/ProbeMode.h b/nping/ProbeMode.h index f4095e5c8..1617b2a10 100644 --- a/nping/ProbeMode.h +++ b/nping/ProbeMode.h @@ -110,7 +110,6 @@ class ProbeMode { static int createIPv4(IPv4Header *i, PacketElement *next_element, const char *next_proto, NpingTarget *target); static int createIPv6(IPv6Header *i, PacketElement *next_element, const char *next_proto, NpingTarget *target); - static int doIPv6ThroughSocket(int rawfd); static int fillPacket(NpingTarget *target, u16 port, u8 *buff, int bufflen, int *filledlen, int rawfd); static int fillPacketTCP(NpingTarget *target, u16 port, u8 *buff, int bufflen, int *filledlen, int rawfd); static int fillPacketUDP(NpingTarget *target, u16 port, u8 *buff, int bufflen, int *filledlen, int rawfd); diff --git a/nping/utils_net.cc b/nping/utils_net.cc index 94cda86ad..245bd5794 100644 --- a/nping/utils_net.cc +++ b/nping/utils_net.cc @@ -375,8 +375,6 @@ bool isICMPCode(u8 code, u8 type){ const char *arppackethdrinfo(const u8 *packet, u32 len, int detail ); int arppackethdrinfo(const u8 *packet, u32 len, u8 *dstbuff, u32 dstlen); -int tcppackethdrinfo(const u8 *packet, size_t len, u8 *dstbuff, size_t dstlen, int detail, const char *src, const char *dst); -int udppackethdrinfo(const u8 *packet, size_t len, u8 *dstbuff, size_t dstlen, int detail, const char *src, const char *dst); /* This function fills buffer "dstbuff" with a printable string that * represents the supplied packet. When sending IPv6 packet at raw TCP @@ -398,39 +396,12 @@ int getPacketStrInfo(const char *proto, const u8 *packet, u32 len, u8 *dstbuff, else detail=LOW_DETAIL; - if( !strcasecmp(proto, "IP") || !strcasecmp(proto, "IPv4") || !strcasecmp(proto, "IPv6")){ - b=(char *)ippackethdrinfo(packet, len, detail); - strncpy((char*)dstbuff, b, dstlen); - dstbuff[dstlen-1]=0; /* Just to be sure, NULL-terminate the last position*/ - }else if( !strcasecmp(proto, "ARP") || !strcasecmp(proto, "RARP") ){ + if( !strcasecmp(proto, "ARP") || !strcasecmp(proto, "RARP") ){ return arppackethdrinfo(packet, len, dstbuff, dstlen); - }else if( !strcasecmp(proto, "IPv6_NO_HEADER") || o.ipv6UsingSocket() ){ - char srcipstring[128]; - const char *src = NULL; - char dstipstring[128]; - const char *dst = NULL; - if (ss_src) { - src = inet_ntop_ez(ss_src, sizeof(*ss_src)); - if (src) { - Strncpy(srcipstring, src, sizeof(srcipstring)); - src = srcipstring; - } - } - if (ss_dst) { - dst = inet_ntop_ez(ss_dst, sizeof(*ss_dst)); - if (dst) { - Strncpy(dstipstring, dst, sizeof(dstipstring)); - dst = dstipstring; - } - } - if( o.getMode()==TCP ) - return tcppackethdrinfo(packet, len, dstbuff, dstlen, detail, src, dst); - else if ( o.getMode()==UDP ) - return udppackethdrinfo(packet, len, dstbuff, dstlen, detail, src, dst); - else - nping_fatal(QT_3, "getPacketStrInfo(): Unable to determinate transport layer protocol"); - }else{ - nping_fatal(QT_3, "getPacketStrInfo(): Unknown protocol"); + } + else { + b=(char *)ippackethdrinfo(packet, len, detail); + strncpy((char*)dstbuff, b, dstlen-1); } return OP_SUCCESS; } /* getPacketStrInfo() */ @@ -903,27 +874,6 @@ int arppackethdrinfo(const u8 *packet, u32 len, u8 *dstbuff, u32 dstlen){ } /* End of arppackethdrinfo() */ -int tcppackethdrinfo(const u8 *packet, size_t len, u8 *dstbuff, size_t dstlen, - int detail, const char *src, const char *dst){ - assert(packet); - assert(dstbuff); - - return (tcppackethdrinfo(packet, len, (char *)dstbuff, dstlen, - detail, 0, src, dst) > 0 ? OP_SUCCESS : OP_FAILURE); -} /* End of tcppackethdrinfo() */ - - -int udppackethdrinfo(const u8 *packet, size_t len, u8 *dstbuff, size_t dstlen, - int detail, const char *src, const char *dst){ - - assert(packet); - assert(dstbuff); - - return (udppackethdrinfo(packet, len, (char *)dstbuff, dstlen, - detail, 0, src, dst) > 0 ? OP_SUCCESS : OP_FAILURE); -} /* End of udppackethdrinfo() */ - - /** Returns a random (null-terminated) ASCII string with no special * meaning. Returned string may be between 1 and 512 bytes and contain * random letters and some whitespace. @@ -969,33 +919,7 @@ int send_packet(NpingTarget *target, int rawfd, u8 *pkt, size_t pktLen){ memset(&s6, 0, sizeof(struct sockaddr_in6)); s6.sin6_family=AF_INET6; s6.sin6_addr = target->getIPv6Address(); - - /* - if( o.getMode()==TCP ){ - dport=getDstPortFromTCPHeader(pkt, pktLen); - if(dport!=NULL) - s6.sin6_port = *dport; - else - nping_fatal(QT_3, "send_packet(): Could not determine TCP destination port."); - } - else if( o.getMode()==UDP){ - dport=getDstPortFromUDPHeader(pkt, pktLen); - if(dport!=NULL) - s6.sin6_port = *dport; - else - nping_fatal(QT_3, "send_packet(): Could not determine UDP destination port."); - } - */ - - /* Linux doesn't seem to like sin6_port to be set to other value - * than 0. Unless we set it to zero, the sendto() call returns - * "Invalid argument" error. Does this happen in other systems? - * TODO: Should we check here if #ifdef LINUX and set the port to - * zero? */ - s6.sin6_port=0; - - res = Sendto("send_packet", rawfd, pkt, pktLen, 0, (struct sockaddr *)&s6, (int) sizeof(struct sockaddr_in6)); - /*Sendto returns errors as -1 according to netutil.cc so lets catch that and return OP_FAILURE*/ + res = send_ipv6_packet_eth_or_sd(rawfd, NULL, &s6, pkt, pktLen); if (res == -1) return OP_FAILURE; }else{ /* IPv4 */ struct sockaddr_storage dst;