scan_engine.cc

来自「Ubuntu packages of security software。 相」· CC 代码 · 共 1,755 行 · 第 1/5 页

CC
1,755
字号
	     flagbuf);    break;  case PS_UDP:    Snprintf(buf, bufsz, "udp to port %hu", pspec->pd.udp.dport);    break;  case PS_PROTO:    Snprintf(buf, bufsz, "protocol %u", (unsigned int) pspec->proto);    break;  case PS_ICMP:    Snprintf(buf, bufsz, "icmp type %d code %d",             pspec->pd.icmp.type, pspec->pd.icmp.code);    break;  case PS_ARP:    Snprintf(buf, bufsz, "ARP");    break;  case PS_CONNECTTCP:    Snprintf(buf, bufsz, "connect to port %hu", pspec->pd.tcp.dport);    break;  default:    fatal("Unexpected %s type encountered", __func__);    break;  }  return buf;  }ConnectProbe::ConnectProbe() {  sd = -1;}ConnectProbe::~ConnectProbe() {  if (sd > 0) close(sd);  sd = -1;}UltraProbe::UltraProbe() {  type = UP_UNSET;  tryno = 0;  timedout = false;  retransmitted = false;  pingseq = 0;  mypspec.type = PS_NONE;  memset(&sent, 0, sizeof(prevSent));  memset(&prevSent, 0, sizeof(prevSent));}UltraProbe::~UltraProbe() {  if (type == UP_CONNECT)    delete probes.CP;}/* Pass an arp packet, including ethernet header. Must be 42bytes */void UltraProbe::setARP(u8 *arppkt, u32 arplen) {  type = UP_ARP;  mypspec.type = PS_ARP;  return;} /* Sets this UltraProbe as type UP_IP and creates & initializes the     internal IPProbe.  The relevent probespec is necessary for setIP     because pspec.type is ambiguous with just the ippacket (e.g. a     tcp packet could be PS_PROTO or PS_TCP). */void UltraProbe::setIP(u8 *ippacket, u32 iplen, const probespec *pspec) {  struct ip *ipv4 = (struct ip *) ippacket;  struct tcp_hdr *tcp = NULL;  struct udp_hdr *udp = NULL;  type = UP_IP;  if (ipv4->ip_v != 4)    fatal("Bogus packet passed to %s -- only IPv4 packets allowed", 	  __func__);  assert(iplen >= 20);  assert(iplen == (u32) ntohs(ipv4->ip_len));  probes.IP.ipid = ntohs(ipv4->ip_id);  if (ipv4->ip_p == IPPROTO_TCP) {    assert (iplen >= (unsigned) ipv4->ip_hl * 4 + 20);        tcp = (struct tcp_hdr *) ((u8 *) ipv4 + ipv4->ip_hl * 4);    probes.IP.pd.tcp.sport = ntohs(tcp->th_sport);    probes.IP.pd.tcp.seq = ntohl(tcp->th_seq);  } else if (ipv4->ip_p == IPPROTO_UDP) {    assert(iplen >= (unsigned) ipv4->ip_hl * 4 + 8);    udp = (struct udp_hdr *) ((u8 *) ipv4 + ipv4->ip_hl * 4);    probes.IP.pd.udp.sport = ntohs(udp->uh_sport);  }  mypspec = *pspec;  return;}u32 UltraProbe::tcpseq() {  if (mypspec.proto == IPPROTO_TCP)    return probes.IP.pd.tcp.seq;  else    fatal("Bogus seq number request to %s -- type is %s", __func__, 	  pspectype2ascii(mypspec.type));  return 0; // Unreached}/* Sets this UltraProbe as type UP_CONNECT, preparing to connect to given   port number*/void UltraProbe::setConnect(u16 portno) {  type = UP_CONNECT;  probes.CP = new ConnectProbe();  mypspec.type = PS_CONNECTTCP;  mypspec.proto = IPPROTO_TCP;  mypspec.pd.tcp.dport = portno;  mypspec.pd.tcp.flags = TH_SYN;}ConnectScanInfo::ConnectScanInfo() {  maxValidSD = -1;  numSDs = 0;  maxSocketsAllowed = (o.max_parallelism)? o.max_parallelism : MAX(5, max_sd() - 4);  FD_ZERO(&fds_read);  FD_ZERO(&fds_write);  FD_ZERO(&fds_except);}/* Nothing really to do here. */ConnectScanInfo::~ConnectScanInfo() {}/* Watch a socket descriptor (add to fd_sets and maxValidSD).  Returns   true if the SD was absent from the list, false if you tried to   watch an SD that was already being watched. */bool ConnectScanInfo::watchSD(int sd) {  assert(sd >= 0);  if (!FD_ISSET(sd, &fds_read)) {    FD_SET(sd, &fds_read);    FD_SET(sd, &fds_write);    FD_SET(sd, &fds_except);    numSDs++;    if (sd > maxValidSD)      maxValidSD = sd;  } else return false;  return true;}/* Clear SD from the fd_sets and maxValidSD.  Returns true if the SD   was in the list, false if you tried to clear an sd that wasn't   there in the first place. */bool ConnectScanInfo::clearSD(int sd) {  assert(sd >= 0);  if (FD_ISSET(sd, &fds_read)) {    FD_CLR(sd, &fds_read);    FD_CLR(sd, &fds_write);    FD_CLR(sd, &fds_except);    assert(numSDs > 0);    numSDs--;    if (sd == maxValidSD)      maxValidSD--;  } else return false;  return true;}GroupScanStats::GroupScanStats(UltraScanInfo *UltraSI) {  memset(&latestip, 0, sizeof(latestip));  memset(&timeout, 0, sizeof(timeout));  USI = UltraSI;  init_ultra_timing_vals(&timing, TIMING_GROUP, USI->numIncompleteHosts(), &(USI->perf), &USI->now);  initialize_timeout_info(&to);  /* Default timout should be much lower for arp */  if (USI->ping_scan_arp)    to.timeout = MIN(o.initialRttTimeout(), 100) * 1000;  num_probes_active = 0;  numtargets = USI->numIncompleteHosts(); // They are all incomplete at the beginning  numprobes = USI->numProbesPerHost();    if (USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan)    CSI = new ConnectScanInfo;  else CSI = NULL;  probes_sent = probes_sent_at_last_wait = 0;  probes_replied_to = 0;  lastping_sent = lastrcvd = USI->now;  lastping_sent_numprobes = 0;  pinghost = NULL;  gettimeofday(&last_wait, NULL);  num_hosts_timedout = 0;}GroupScanStats::~GroupScanStats() {  delete CSI;}  /* Returns true if the GLOBAL system says that sending is OK.*/bool GroupScanStats::sendOK() {  int recentsends;  if ((USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan)      && CSI->numSDs >= CSI->maxSocketsAllowed)    return false;  /* We need to stop sending if it has been a long time since     the last listen call, at least for systems such as Windoze that     don't give us a proper pcap time.  Also for connect scans, since     we don't get an exact response time with them either. */  recentsends = USI->gstats->probes_sent - USI->gstats->probes_sent_at_last_wait;  if (recentsends > 0 &&       (USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan || !pcap_recv_timeval_valid())) {    int to_ms = (int) MAX(to.srtt * .75 / 1000, 50);    if (TIMEVAL_MSEC_SUBTRACT(USI->now, last_wait) > to_ms)      return false;  }  /* There are good arguments for limiting the number of probes sent     between waits even when we do get appropriate receive times.  For     example, overflowing the pcap receive buffer with responses is no     fun.  On one of my Linux boxes, it seems to hold about 113     responses when I scan localhost.  And half of those are the @#$#     sends being received.  I think I'll put a limit of 50 sends per     wait */  if (recentsends >= 50)    return false;  /* When there is only one target left, let the host congestion     stuff deal with it. */  if (USI->numIncompleteHostsLessThan(2))    return true;  if (timing.cwnd >= num_probes_active + 0.5)    return true;  return false;}/* Returns the scaling factor to use when incrementing the congestion window.   This is the minimum of probes_sent / probes_replied_to and cc_scale_max. */double GroupScanStats::cc_scale() {  double ratio;  if (probes_replied_to == 0)    return USI->perf.cc_scale_max;  ratio = (double) probes_sent / probes_replied_to;  return MIN(ratio, USI->perf.cc_scale_max);}/* For the given scan type, this returns the port/host state demonstrated   by getting no response back */static int scantype_no_response_means(stype scantype) {  switch(scantype) {  case SYN_SCAN:  case ACK_SCAN:  case WINDOW_SCAN:  case CONNECT_SCAN:    return PORT_FILTERED;  case UDP_SCAN:  case IPPROT_SCAN:  case NULL_SCAN:  case FIN_SCAN:  case MAIMON_SCAN:  case XMAS_SCAN:    return PORT_OPENFILTERED;  case PING_SCAN:  case PING_SCAN_ARP:    return HOST_DOWN;  default:    fatal("Unexpected scan type found in %s()", __func__);  }  return 0; /* Unreached */}HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) {   target = t;   USI=UltraSI;   next_portidx = 0;   sent_arp = false;  next_ackportpingidx = 0;  next_synportpingidx = 0;  next_udpportpingidx = 0;  next_protoportpingidx = 0;  sent_icmp_ping = false;  sent_icmp_mask = false;  sent_icmp_ts = false;  num_probes_active = 0;   num_probes_waiting_retransmit = 0;  lastping_sent = lastprobe_sent = lastrcvd = USI->now;  lastping_sent_numprobes = 0;  memset(&pingprobe, 0, sizeof(pingprobe));  pingprobestate = PORT_UNKNOWN;  nxtpseq = 1;  max_successful_tryno = 0;  tryno_mayincrease = true;  ports_finished = 0;  numprobes_sent = 0;  numpings_sent = 0;  numprobes_replied_to = 0;  init_ultra_timing_vals(&timing, TIMING_HOST, 1, &(USI->perf), &USI->now);  bench_tryno = 0;  memset(&sdn, 0, sizeof(sdn));  sdn.last_boost = USI->now;  sdn.delayms = o.scan_delay;  rld.max_tryno_sent = 0;  rld.rld_waiting = false;  rld.rld_waittime = USI->now;}HostScanStats::~HostScanStats() {  list<UltraProbe *>::iterator probeI, next;/* Move any hosts from the bench to probes_outstanding for easier deletion  */  for(probeI = probes_outstanding.begin(); probeI != probes_outstanding.end();       probeI = next) {    next = probeI;    next++;    destroyOutstandingProbe(probeI);  }}/* How long I am currently willing to wait for a probe response before   considering it timed out.  Uses the host values from target if they   are available, otherwise from gstats.  Results returned in   MICROseconds.  */unsigned long HostScanStats::probeTimeout() {  if (target->to.srtt > 0) {    /* We have at least one timing value to use.  Good enough, I suppose */    return target->to.timeout;  } else if (USI->gstats->to.srtt > 0) {    /* OK, we'll use this one instead */    return USI->gstats->to.timeout;  } else {    return target->to.timeout; /* It comes with a default */  }}  /* How long I'll wait until completely giving up on a probe.     Timedout probes are often marked as such (and sometimes     considered a drop), but kept in the list just in case they come     really late.  But after probeExpireTime(), I don't waste time     keeping them around. Give in MICROseconds. The expiry time can     depend on the type of probe. Pass NULL to get the default time. */unsigned long HostScanStats::probeExpireTime(const UltraProbe *probe) {  if (probe == NULL || probe->type == UltraProbe::UP_CONNECT)    /* timedout probes close socket -- late resp. impossible */    return probeTimeout();  else    /* Wait a bit longer after probeTimeout. */    return MIN(10000000, probeTimeout() * 10);}/* Returns OK if sending a new probe to this host is OK (to avoid   flooding). If when is non-NULL, fills it with the time that sending   will be OK assuming no pending probes are resolved by responses   (call it again if they do).  when will become now if it returns   true. */bool HostScanStats::sendOK(struct timeval *when) {  struct ultra_timing_vals tmng;  int packTime;  list<UltraProbe *>::iterator probeI;  struct timeval probe_to, earliest_to, sendTime;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?