mirror of
https://github.com/nmap/nmap.git
synced 2026-10-21 11:22:05 +00:00
Use libnetutil's IPv6 sending for Nping
This commit is contained in:
parent
fc305b0187
commit
60592283d3
5 changed files with 30 additions and 247 deletions
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -372,7 +372,6 @@ class NpingOps {
|
|||
bool issetIPVersion();
|
||||
bool ipv4();
|
||||
bool ipv6();
|
||||
bool ipv6UsingSocket();
|
||||
int af();
|
||||
|
||||
/* Privileges */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue