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 + -
显示快捷键?