#include "rndRange.h" rndRange::rndRange(int maxHosts) : _mMaxHosts(maxHosts), _mTotalRange(0), _mFullScan(false) { if(_mMaxHosts<1){ fatal("Error. You must scan atleast one host."); } for(int i=0;i<256;i++){ _mHostsScanned[i]=new _sHostsScanned; _mHostsScanned[i]->ip=0; _mHostsScanned[i]->next=NULL; } } rndRange::~rndRange() { if(_mRanges[0]!=NULL){ delete [] _mRanges[0]; delete [] _mRanges[1]; } } /** * Returns 1 if this is a reserved IP address, where "reserved" means * either a private address, non-routable address, or even a non-reserved * but unassigned address which has an extremely high probability of being * black-holed. * * We try to optimize speed when ordering the tests. This optimization * assumes that all byte values are equally likely in the input. * * Warning: This function could easily become outdated if the IANA * starts to assign some more IPv4 ranges to RIPE, etc. as they have * started doing this year (2001), for example 80.0.0.0/4 used to be * completely unassigned until they gave 80.0.0.0/7 to RIPE in April * 2001 (www.junk.org is an example of a new address in this range). * * Check for * the most recent assigments and * for bogon * netblocks. */ //ripped right out of nmap.cc bool rndRange::ip_is_reserved(struct in_addr &ip) { char *ipc = (char *) &(ip.s_addr); unsigned char i1 = ipc[0], i2 = ipc[1], i3 = ipc[2], i4 = ipc[3]; /* do all the /7's and /8's with a big switch statement, hopefully the * compiler will be able to optimize this a little better using a jump table * or what have you */ switch (i1) { case 0: /* 000/8 is IANA reserved */ case 1: /* 001/8 is IANA reserved */ case 2: /* 002/8 is IANA reserved */ case 5: /* 005/8 is IANA reserved */ case 6: /* USA Army ISC */ case 7: /* used for BGP protocol */ case 10: /* the infamous 10.0.0.0/8 */ case 14: /* 014/8 is IANA reserved */ case 23: /* 023/8 is IANA reserved */ case 27: /* 027/8 is IANA reserved */ case 31: /* 031/8 is IANA reserved */ case 36: /* 036/8 is IANA reserved */ case 37: /* 037/8 is IANA reserved */ case 39: /* 039/8 is IANA reserved */ case 42: /* 042/8 is IANA reserved */ case 46: /* 046/8 is IANA reserved */ case 49: /* 049/8 is IANA reserved */ case 50: /* 050/8 is IANA reserved */ case 55: /* misc. U.S.A. Armed forces */ case 127: /* 127/8 is reserved for loopback */ case 197: /* 197/8 is IANA reserved */ case 223: /* 223/8 is IANA reserved */ return true; default: break; } /* 100-111/8 is IANA reserved */ if (i1 >= 100 && i1 <= 111) return true; /* 172.16.0.0/12 is reserved for private nets by RFC1819 */ if (i1 == 172 && i2 >= 16 && i2 <= 31) return true; /* 175-185/8 is IANA reserved */ if (i1 >= 175 && i1 <= 185) return true; /* 192.168.0.0/16 is reserved for private nets by RFC1819 */ /* 192.0.2.0/24 is reserved for documentation and examples */ /* 192.88.99.0/24 is used as 6to4 Relay anycast prefix by RFC3068 */ if (i1 == 192) { if (i2 == 168) return true; if (i2 == 0 && i3 == 2) return true; if (i2 == 88 && i3 == 99) return true; } /* 198.18.0.0/15 is used for benchmark tests by RFC2544 */ if (i1 == 198 && i2 == 18 && i3 >= 1 && i3 <= 64) { return true; } /* reserved for DHCP clients seeking addresses, not routable outside LAN */ if (i1 == 169 && i2 == 254) return true; /* believe it or not, 204.152.64.0/23 is some bizarre Sun proprietary * clustering thing */ if (i1 == 204 && i2 == 152 && (i3 == 64 || i3 == 65)) return true; /* 224-239/8 is all multicast stuff */ /* 240-255/8 is IANA reserved */ if (i1 >= 224) return true; /* 255.255.255.255, note we already tested for i1 in this range */ if (i2 == 255 && i3 == 255 && i4 == 255) return true; return false; } //large portions of this function are adapted from TargetGroup::parse_expr void rndRange::addRange(char **Options, const int &Pointer, const int &limit){ bool illegal; struct in_addr startaddr; int netmask; char * s; char *target_net; std::vector beginrangeList; std::vector endrangeList; for(int q=Pointer;q 32) { error("Illegal netmask value (%d), must be /0 - /32 . Assuming /32 (one host)", netmask); netmask = 32; } //read addresses, right now we only support CIDR form inet_pton(AF_INET, target_net, &(startaddr)); if (netmask) { unsigned long longtmp = ntohl(startaddr.s_addr); beginrangeList.push_back( longtmp & (unsigned long) (0 - (1<<(32 - netmask))) ); endrangeList.push_back( longtmp | (unsigned long) ((1<<(32 - netmask)) - 1) ); } else { /* The above calculations don't work for a /0 netmask, though at first * glance it appears that they would */ beginrangeList.push_back(0); endrangeList.push_back(0xffffffff); } if (beginrangeList.back() <= endrangeList.back()) { _mTotalRange += (unsigned long long) (endrangeList.back() - beginrangeList.back()) + 1; free(hostexp); continue; } error("Host specification invalid"); free(hostexp); } if(!beginrangeList.empty()){ _mRanges[0]=new unsigned int[beginrangeList.size()]; _mRanges[1]=new unsigned int[endrangeList.size()]; _mSzRanges=beginrangeList.size(); for(int j=0; !beginrangeList.empty(); j++){ _mRanges[0][j]=beginrangeList.back(); beginrangeList.pop_back(); _mRanges[1][j]=endrangeList.back(); endrangeList.pop_back(); } }else{ _mRanges[0]=new unsigned int[1]; _mRanges[1]=new unsigned int[1]; _mSzRanges=1; _mRanges[0][0]=0; _mRanges[1][0]=0xffffffff; _mTotalRange =0xffffffff; _mFullScan=true; } if(_mMaxHosts>_mTotalRange) fatal("Error. Cannot scan %u hosts when list only containts %u hosts",_mMaxHosts,_mTotalRange); } void rndRange::getRandHost(struct in_addr &ip){ _sHostsScanned * HEAD=NULL; do{ bool repeat=false; unsigned int nextHost = get_random_u32()%_mTotalRange; for(unsigned int i=0;i<_mSzRanges;i++){ if(_mRanges[0][i]+nextHost<_mRanges[1][i]){ nextHost+=_mRanges[0][i]; break; }else{ nextHost=nextHost +_mRanges[0][i]-_mRanges[1][i]; } } //dont scan protected IP's when scanning the full range if(_mFullScan){ ip.s_addr = htonl(nextHost); if(ip_is_reserved(ip)) continue; } HEAD=_mHostsScanned[nextHost%256]; while(HEAD->next!=NULL){ if(HEAD->ip==nextHost){ repeat=true; break; } HEAD=HEAD->next; } if(!repeat){ HEAD->next=new _sHostsScanned; HEAD->ip=nextHost; HEAD->next->next=NULL; ip.s_addr = htonl(nextHost); return; } }while(true); }