Nmap源碼分析(整體架構)

整體架構

功能目錄

docs :相關文檔
libdnet-stripped :開源網絡接口庫
liblinear:開源大型線性分類庫
liblua:開源Lua腳本語言庫
libnetutil:基本的網絡函數
libpcap:開源抓包庫
libpcre:開源正則表達式庫
macosx:xcode項目文件
mswin32:vs項目文件
nbase:Nmap封裝的基礎使用函數庫
ncat:netcat網絡工具,由Nmap實現
ndiff:比較Nmap掃描結果的實用命令
nmap-update:負責Nmap更新操作
nping:Nmap項目組實現的新版的Hping,探測與構建包
nselib:Nmap的Lua腳本
nsock:Nmap實現的並行的SocketEvent處理庫
scripts:Nmap提供常用的掃描檢查的lua腳本
todo:開發任務
zenmap:python的圖形界面程序

主體程序邏輯

入口程序在main.cc,主要功能

  • 檢查環境變量NMAP_ARGS
  • 檢查有沒有–resume參數
  • 判斷是resume之前掃描,還是新請求

然後是根據傳入參數去調用 nmap.cc的nmap_main()函數。下面是精簡後的源碼:


int main(int argc, char *argv[]) {
  char command[2048];
  int myargc;
  char **myargv = NULL;
  char *cptr;
  int ret;
  int i;

  set_program_name(argv[0]);

  if ((cptr = getenv("NMAP_ARGS"))) {
    if (Snprintf(command, sizeof(command), "nmap %s", cptr) >= (int) sizeof(command)) {
        error("Warning: NMAP_ARGS variable is too long, truncated");
    }
    /* copy rest of command-line arguments */
    for (i = 1; i < argc && strlen(command) + strlen(argv[i]) + 1 < sizeof(command); i++) {
      strcat(command, " ");
      strcat(command, argv[i]);
    }
    myargc = arg_parse(command, &myargv);
    if (myargc < 1) {
      fatal("NMAP_ARGS variable could not be parsed");
    }
    ret = nmap_main(myargc, myargv);
    arg_parse_free(myargv);
    return ret;
  }

  if (argc == 3 && strcmp("--resume", argv[1]) == 0) {
    if (gather_logfile_resumption_state(argv[2], &myargc, &myargv) == -1) {
      fatal("Cannot resume from (supposed) log file %s", argv[2]);
    }
    return nmap_main(myargc, myargv);
  }

  return nmap_main(argc, argv);
}

然後程序教育nmap_main().
nmap_main裏,表面看起來掃描的循環是從2065行開始:

for (targetno = 0; targetno < Targets.size(); targetno++) {
currenths = Targets[targetno];
前後的代碼都比較多,下次再抽時間細緻分析。

這裏引用一個別人做的流程圖:

主體程序位置在nmap.cc內的nmap_main函數

新建一個主機的單例對象

#ifndef NOLUA
  /* Only NSE scripts can add targets */
  NewTargets *new_targets = NULL;
  /* Pre-Scan and Post-Scan script results datastructure */
  ScriptResults *script_scan_results = NULL;
#endif

開始主程序

Target類

target.cc定義的是主機的類,掃描信息也是保存在target對象。nmap_main創建target時,使用了單例模式。

int nmap_main(int argc, char *argv[]) {
  int i;
  std::vector<Target *> Targets;
  time_t now;
  struct hostent *target = NULL;
  time_t timep;
  char mytime[128];
  struct addrset *exclude_group;
#ifndef NOLUA
  /* Only NSE scripts can add targets */
  NewTargets *new_targets = NULL;
  /* Pre-Scan and Post-Scan script results datastructure */
  ScriptResults *script_scan_results = NULL;
#endif
  unsigned int ideal_scan_group_sz = 0;
  Target *currenths;
  char myname[FQDN_LEN + 1];
  int sourceaddrwarning = 0; /* Have we warned them yet about unguessable
                                source addresses? */
  unsigned int targetno;
  char hostname[FQDN_LEN + 1] = "";
  struct sockaddr_storage ss;
  size_t sslen;

#ifdef LINUX
  /* Check for WSL and warn that things may not go well. */
  struct utsname uts;
  if (!uname(&uts)) {
    if (strstr(uts.release, "Microsoft") != NULL) {
      error("Warning: %s may not work correctly on Windows Subsystem for Linux.\n"
          "For best performance and accuracy, use the native Windows build from %s/download.html#windows.",
          NMAP_NAME, NMAP_URL);
    }
  }
#endif

  now = time(NULL);
  local_time = localtime(&now);

  if (o.debugging)
    nbase_set_log(fatal, error);
  else
    nbase_set_log(fatal, NULL);

  if (argc < 2){
    printusage();
    exit(-1);
  }

  Targets.reserve(100);
#ifdef WIN32
  win_pre_init();
#endif

  // 命令行參數解析
  printf("命令行參數解析\n");
  parse_options(argc, argv);

  // Linux平臺設置只讀非堵塞
  printf("Linux平臺設置只讀非堵塞\n");
  tty_init(); // Put the keyboard in raw mode

#ifdef WIN32
  // Must come after parse_options because of --unprivileged
  // Must come before apply_delayed_options because it sets o.isr00t
  win_init();
#endif

  // 延遲處理的操作
  printf("延遲處理的操作\n");
  apply_delayed_options();

/* 
這裏用到的變量route_dst_hosts是由參數 --route-dst debugging模式定義的目標列表。定義如下: 
static std::vector<std::string> route_dst_hosts;
前面命令行解析後會對其賦值。
*/

  for (unsigned int i = 0; i < route_dst_hosts.size(); i++) {
    const char *dst;
    struct sockaddr_storage ss;
    struct route_nfo rnfo;
    size_t sslen;
    int rc;

    dst = route_dst_hosts[i].c_str();
    printf("解析參數 route_dst_hosts:%s\n", dst);

    // 解析目標
    printf("解析目標\n");
    rc = resolve(dst, 0, &ss, &sslen, o.af());
    if (rc != 0)
      fatal("Can't resolve %s: %s.", dst, gai_strerror(rc));

    printf("%s\n", inet_ntop_ez(&ss, sslen));

    if (!route_dst(&ss, &rnfo, o.device, o.SourceSockAddr())) {
      printf("Can't route %s (%s).", dst, inet_ntop_ez(&ss, sslen));
    } else {
      printf("%s %s", rnfo.ii.devname, rnfo.ii.devfullname);
      printf(" srcaddr %s", inet_ntop_ez(&rnfo.srcaddr, sizeof(rnfo.srcaddr)));
      if (rnfo.direct_connect)
        printf(" direct");
      else
        printf(" nexthop %s", inet_ntop_ez(&rnfo.nexthop, sizeof(rnfo.nexthop)));
    }
    printf("\n");
  }
  route_dst_hosts.clear();

  if (delayed_options.iflist) {
    print_iflist();
    exit(0);
  }

  /* If he wants to bounce off of an FTP site, that site better damn well be reachable! */
  // FTP bounce scan模式,nmap -b參數定義
  if (o.bouncescan) {
    printf("nmap -b參數\n");
    if (!inet_pton(AF_INET, ftp.server_name, &ftp.server)) {
      if ((target = gethostbyname(ftp.server_name)))
        memcpy(&ftp.server, target->h_addr_list[0], 4);
      else {
        fatal("Failed to resolve FTP bounce proxy hostname/IP: %s",
              ftp.server_name);
      }
    } else if (o.verbose) {
      log_write(LOG_STDOUT, "Resolved FTP bounce attack proxy to %s (%s).\n",
                ftp.server_name, inet_ntoa(ftp.server));
    }
  }
  fflush(stdout);
  fflush(stderr);

  timep = time(NULL);

  // 掃描的簡要信息 記錄到xml
  Strncpy(mytime, ctime(&timep), sizeof(mytime));
  chomp(mytime);

  if (!o.resuming) {
    /* Brief info in case they forget what was scanned */
    char *xslfname = o.XSLStyleSheet();
    xml_start_document("nmaprun");
    if (xslfname) {
      xml_open_pi("xml-stylesheet");
      xml_attribute("href", "%s", xslfname);
      xml_attribute("type", "text/xsl");
      xml_close_pi();
      xml_newline();
    }

    xml_start_comment();
    xml_write_escaped(" %s %s scan initiated %s as: %s ", NMAP_NAME, NMAP_VERSION, mytime, join_quoted(argv, argc).c_str());
    xml_end_comment();
    xml_newline();

    xml_open_start_tag("nmaprun");
    xml_attribute("scanner", "nmap");
    xml_attribute("args", "%s", join_quoted(argv, argc).c_str());
    xml_attribute("start", "%lu", (unsigned long) timep);
    xml_attribute("startstr", "%s", mytime);
    xml_attribute("version", "%s", NMAP_VERSION);
    xml_attribute("xmloutputversion", NMAP_XMLOUTPUTVERSION);
    xml_close_start_tag();
    xml_newline();

    output_xml_scaninfo_records(&ports);

    xml_open_start_tag("verbose");
    xml_attribute("level", "%d", o.verbose);
    xml_close_empty_tag();
    xml_newline();
    xml_open_start_tag("debugging");
    xml_attribute("level", "%d", o.debugging);
    xml_close_empty_tag();
    xml_newline();
  } else {
    xml_start_tag("nmaprun", false);
  }

  // 記錄掃描日誌
  printf("記錄掃描日誌\n");
  log_write(LOG_NORMAL | LOG_MACHINE, "# ");
  log_write(LOG_NORMAL | LOG_MACHINE, "%s %s scan initiated %s as: %s", NMAP_NAME, NMAP_VERSION, mytime, join_quoted(argv, argc).c_str());
  log_write(LOG_NORMAL | LOG_MACHINE, "\n");

  /* Before we randomize the ports scanned, lets output them to machine
     parseable output */
  // 在隨機端口掃描前,把可以解析的端口輸出機器
  if (o.verbose)
  {
    printf("在隨機端口掃描前,把可以解析的端口輸出機器\n");
    output_ports_to_machine_parseable_output(&ports);
  }

#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
  signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE so our program doesn't crash because
                               of it, but we really shouldn't get an unexpected
                               SIGPIPE */
#endif

  if (o.max_parallelism && (i = max_sd()) && i < o.max_parallelism) {
    error("WARNING: Your specified max_parallel_sockets of %d, but your system says it might only give us %d.  Trying anyway", o.max_parallelism, i);
  }

  // 端口號是否溢出
  if (o.debugging > 1)
  {
    printf("端口號是否溢出\n");
    log_write(LOG_STDOUT, "The max # of sockets we are using is: %d\n", o.max_parallelism);
  }

  // At this point we should fully know our timing parameters
  if (o.debugging) {
    log_write(LOG_PLAIN, "--------------- Timing report ---------------\n");
    log_write(LOG_PLAIN, "  hostgroups: min %d, max %d\n", o.minHostGroupSz(), o.maxHostGroupSz());
    log_write(LOG_PLAIN, "  rtt-timeouts: init %d, min %d, max %d\n", o.initialRttTimeout(), o.minRttTimeout(), o.maxRttTimeout());
    log_write(LOG_PLAIN, "  max-scan-delay: TCP %d, UDP %d, SCTP %d\n", o.maxTCPScanDelay(), o.maxUDPScanDelay(), o.maxSCTPScanDelay());
    log_write(LOG_PLAIN, "  parallelism: min %d, max %d\n", o.min_parallelism, o.max_parallelism);
    log_write(LOG_PLAIN, "  max-retries: %d, host-timeout: %ld\n", o.getMaxRetransmissions(), o.host_timeout);
    log_write(LOG_PLAIN, "  min-rate: %g, max-rate: %g\n", o.min_packet_send_rate, o.max_packet_send_rate);
    log_write(LOG_PLAIN, "---------------------------------------------\n");
  }

  /* Before we randomize the ports scanned, we must initialize PortList class. */
  // 端口與地址初始化
  if (o.ipprotscan)
  {
    printf("端口與地址初始化\n");
    PortList::initializePortMap(IPPROTO_IP,  ports.prots, ports.prot_count);
  }
  if (o.TCPScan())
    PortList::initializePortMap(IPPROTO_TCP, ports.tcp_ports, ports.tcp_count);
  if (o.UDPScan())
    PortList::initializePortMap(IPPROTO_UDP, ports.udp_ports, ports.udp_count);
  if (o.SCTPScan())
    PortList::initializePortMap(IPPROTO_SCTP, ports.sctp_ports, ports.sctp_count);

  // 打亂端口順序
  if (o.randomize_ports) {
    printf("打亂端口順序\n");
    if (ports.tcp_count) {
      shortfry(ports.tcp_ports, ports.tcp_count);
      // move a few more common ports closer to the beginning to speed scan
      // 常見端口往前放
      printf("常見端口往前放\n");
      random_port_cheat(ports.tcp_ports, ports.tcp_count);
    }
    if (ports.udp_count)
      shortfry(ports.udp_ports, ports.udp_count);
    if (ports.sctp_count)
      shortfry(ports.sctp_ports, ports.sctp_count);
    if (ports.prot_count)
      shortfry(ports.prots, ports.prot_count);
  }

  // --exclude_group 命令行參數:排除地址處理(排除主機或網絡)
  printf("--exclude_group 命令行參數:排除地址處理(排除主機或網絡)\n");
  exclude_group = addrset_new();

  /* lets load our exclude list */
  if (o.excludefd != NULL) {
    load_exclude_file(exclude_group, o.excludefd);
    fclose(o.excludefd);
  }
  if (o.exclude_spec != NULL) {
    load_exclude_string(exclude_group, o.exclude_spec);
  }

  if (o.debugging > 3)
    dumpExclude(exclude_group);

// NES 環境
printf("NES 環境\n");
#ifndef NOLUA
  if (o.scriptupdatedb) {
    o.max_ips_to_scan = o.numhosts_scanned; // disable warnings?
  }

  // 版本掃描
  if (o.servicescan)
  {
    printf("版本掃描\n");
    o.scriptversion = true;
  }
  if (o.scriptversion || o.script || o.scriptupdatedb)
    open_nse();

  /* Run the script pre-scanning phase */
  // 預分析掃描
  if (o.script) {
    printf("預分析掃描\n");
    new_targets = NewTargets::get();
    script_scan_results = get_script_scan_results_obj();
    script_scan(Targets, SCRIPT_PRE_SCAN);
    printscriptresults(script_scan_results, SCRIPT_PRE_SCAN);
    while (!script_scan_results->empty()) {
      script_scan_results->front().clear();
      script_scan_results->pop_front();
    }
  }
#endif

  if (o.ping_group_sz < o.minHostGroupSz())
    o.ping_group_sz = o.minHostGroupSz();

  // hstate 是一個list,初始爲空,循環執行後保存各主機表達式字符串地址
  HostGroupState hstate(o.ping_group_sz, o.randomize_hosts, argc, (const char **) argv);

  // 主程序循環
  do {

    // 計算 host group 大小
    ideal_scan_group_sz = determineScanGroupSize(o.numhosts_scanned, &ports);

    // 主機發現成功,同加入到 host group,再後續處理
    while (Targets.size() < ideal_scan_group_sz) {
      o.current_scantype = HOST_DISCOVERY;

      // 主機發現
      currenths = nexthost(&hstate, exclude_group, &ports, o.pingtype);

      // 如果沒有發現主機,就進行下一次循環
      if (!currenths)
        break;

      if (currenths->flags & HOST_UP && !o.listscan)
        o.numhosts_up++;

      if ((o.noportscan && !o.traceroute
#ifndef NOLUA
           && !o.script
#endif
          ) || o.listscan) {
        /* We're done with the hosts */
        // 如果 命令行參數-sn(不進行端口掃描) 且沒有指定traceroute和腳本的話,掃描結束
        // 如果 -sL(只列出ip),掃描也結束
        if (currenths->flags & HOST_UP || (o.verbose && !o.openOnly())) {
          xml_start_tag("host");
          write_host_header(currenths);
          printmacinfo(currenths);
          //  if (currenths->flags & HOST_UP)
          //  log_write(LOG_PLAIN,"\n");
          printtimes(currenths);
          xml_end_tag();
          xml_newline();
          log_flush_all();
        }
        delete currenths;
        o.numhosts_scanned++;
        if (!o.max_ips_to_scan || o.max_ips_to_scan > o.numhosts_scanned + Targets.size())
          continue;
        else
          break;
      }

      // -S ip (配置要僞造的IP)
      if (o.spoofsource) {
        printf("-S ip (配置要僞造的IP)\n");
        o.SourceSockAddr(&ss, &sslen);
        currenths->setSourceSockAddr(&ss, sslen);
      }

      /* I used to check that !currenths->weird_responses, but in some
         rare cases, such IPs CAN be port successfully scanned and even
         connected to */
      // 一些情況下,主機有返回狀態,全狀態爲HOST_DOWN
      if (!(currenths->flags & HOST_UP)) {
        printf("一些情況下,主機有返回狀態,全狀態爲HOST_DOWN\n");
        if (o.verbose && (!o.openOnly() || currenths->ports.hasOpenPorts())) {
          xml_start_tag("host");
          write_host_header(currenths);
          xml_end_tag();
          xml_newline();
        }
        delete currenths;
        o.numhosts_scanned++;
        if (!o.max_ips_to_scan || o.max_ips_to_scan > o.numhosts_scanned + Targets.size())
          continue;
        else
          break;
      }

      // RawScan ,如SYN/FIN/ARP
      if (o.RawScan()) {
        printf("RawScan ,如SYN/FIN/ARP \n");
        if (currenths->SourceSockAddr(NULL, NULL) != 0) {
          if (o.SourceSockAddr(&ss, &sslen) == 0) {
            // 直接設置IP
            printf("直接設置IP\n");
            currenths->setSourceSockAddr(&ss, sslen);
          } else {
            // 解析主機名
            printf("解析主機名\n");
            if (gethostname(myname, FQDN_LEN) ||
                resolve(myname, 0, &ss, &sslen, o.af()) != 0)
              fatal("Cannot get hostname!  Try using -S <my_IP_address> or -e <interface to scan through>\n");

            o.setSourceSockAddr(&ss, sslen);
            currenths->setSourceSockAddr(&ss, sslen);
            if (! sourceaddrwarning) {
              error("WARNING: We could not determine for sure which interface to use, so we are guessing %s .  If this is wrong, use -S <my_IP_address>.",
                    inet_socktop(&ss));
              sourceaddrwarning = 1;
            }
          }
        }

        // 網絡設備(網卡)名稱
        if (!currenths->deviceName())
          fatal("Do not have appropriate device name for target");

        /* Hosts in a group need to be somewhat homogeneous. Put this host in
           the next group if necessary. See target_needs_new_hostgroup for the
           details of when we need to split. */
        // 同一個組內主機要是同性質的,這裏判斷目標是否加到list列表內
        if (Targets.size() && target_needs_new_hostgroup(&Targets[0], Targets.size(), currenths)) {
          printf("同一個組內主機要是同性質的,這裏判斷目標是否加到list列表內\n");
          returnhost(&hstate);
          o.numhosts_up--;
          break;
        }
        o.decoys[o.decoyturn] = currenths->source();
      }
      Targets.push_back(currenths);
    }

    // 沒有發現主機
    if (Targets.size() == 0)
    {
      printf("沒有發現主機, break\n");
      break; /* Couldn't find any more targets */
    }

    // Set the variable for status printing
    o.numhosts_scanning = Targets.size();

    // Our source must be set in decoy list because nexthost() call can
    // change it (that issue really should be fixed when possible)
    if (o.RawScan())
    {
      printf("Raw掃描:RawScan\n");
      o.decoys[o.decoyturn] = Targets[0]->source();
    }

    /* I now have the group for scanning in the Targets vector */
    // 定義了端口掃描,進入掃描的主體
    if (!o.noportscan) {
      printf("定義了端口掃描,進入掃描的主體\n");
      // Ultra_scan sets o.scantype for us so we don't have to worry
      if (o.synscan)
      {
        printf("syn掃描:synscan\n");
        ultra_scan(Targets, &ports, SYN_SCAN);
      }

      if (o.ackscan)
      {
        printf("ack掃描:acksan\n");
        ultra_scan(Targets, &ports, ACK_SCAN);
      }

      if (o.windowscan)
      {
        printf("windows掃描:windowscan\n");
        ultra_scan(Targets, &ports, WINDOW_SCAN);
      }

      if (o.finscan)
      {
        printf("fin掃描:finscan\n");
        ultra_scan(Targets, &ports, FIN_SCAN);
      }

      if (o.xmasscan)
      {
        printf("xmas掃描:xmasscan\n");
        ultra_scan(Targets, &ports, XMAS_SCAN);
      }

      if (o.nullscan)
      {
        printf("空掃描:nullscan\n");
        ultra_scan(Targets, &ports, NULL_SCAN);
      }

      if (o.maimonscan)
      {
        printf("maimon 掃描:maimonscan\n");
        ultra_scan(Targets, &ports, MAIMON_SCAN);
      }

      if (o.udpscan)
      {
        printf("udp掃描:udpscan\n");
        ultra_scan(Targets, &ports, UDP_SCAN);
      }

      if (o.connectscan)
      {
        printf("連接掃描:connectscan\n");
        ultra_scan(Targets, &ports, CONNECT_SCAN);
      }

      if (o.sctpinitscan)
      {
        printf("sctp init 掃描:sctpinitscan\n");
        ultra_scan(Targets, &ports, SCTP_INIT_SCAN);
      }

      if (o.sctpcookieechoscan)
      {
        printf("sctp cookit 回顯掃描:sctpcookieechoscan\n");
        ultra_scan(Targets, &ports, SCTP_COOKIE_ECHO_SCAN);
      }

      if (o.ipprotscan)
      {
        printf("ip端口掃描:ipprotscan\n");
        ultra_scan(Targets, &ports, IPPROT_SCAN);
      }

      /* These lame functions can only handle one target at a time */
      // 這些蹩腳的函數一次只能處理一個目標
      if (o.idlescan) {
        printf("idlescan:這些蹩腳的函數一次只能處理一個目標\n");
        for (targetno = 0; targetno < Targets.size(); targetno++) {
          o.current_scantype = IDLE_SCAN;
          keyWasPressed(); // Check if a status message should be printed
          idle_scan(Targets[targetno], ports.tcp_ports,
                    ports.tcp_count, o.idleProxy, &ports);
        }
      }
      if (o.bouncescan) {
        printf("bouncescan:這些蹩腳的函數一次只能處理一個目標\n");
        for (targetno = 0; targetno < Targets.size(); targetno++) {
          o.current_scantype = BOUNCE_SCAN;
          keyWasPressed(); // Check if a status message should be printed
          if (ftp.sd <= 0)
            ftp_anon_connect(&ftp);
          if (ftp.sd > 0)
            bounce_scan(Targets[targetno], ports.tcp_ports, ports.tcp_count, &ftp);
        }
      }

      // 服務掃描
      if (o.servicescan) {
        printf("servicescan:服務掃描\n");
        o.current_scantype = SERVICE_SCAN;
        service_scan(Targets);
      }
    }

    // 系統掃描
    if (o.osscan) {
      printf("osscan:系統掃描\n");
      OSScan os_engine;
      os_engine.os_scan(Targets);
    }

    if (o.traceroute)
    {
      printf("traceroute:跟蹤路由\n");
      traceroute(Targets);
    }

#ifndef NOLUA
    if (o.script || o.scriptversion) {
      printf("script:腳本掃描\n");
      script_scan(Targets, SCRIPT_SCAN);
    }
#endif

    // 輸出掃描結果
    for (targetno = 0; targetno < Targets.size(); targetno++) {
      printf("輸出掃描結果\n");
      currenths = Targets[targetno];
      /* Now I can do the output and such for each host */
      if (currenths->timedOut(NULL)) {
        xml_open_start_tag("host");
        xml_attribute("starttime", "%lu", (unsigned long) currenths->StartTime());
        xml_attribute("endtime", "%lu", (unsigned long) currenths->EndTime());
        xml_close_start_tag();
        write_host_header(currenths);
        xml_end_tag(); /* host */
        xml_newline();
        log_write(LOG_PLAIN, "Skipping host %s due to host timeout\n",
                  currenths->NameIP(hostname, sizeof(hostname)));
        log_write(LOG_MACHINE, "Host: %s (%s)\tStatus: Timeout\n",
                  currenths->targetipstr(), currenths->HostName());
      } else {
        /* --open means don't show any hosts without open ports. */
        if (o.openOnly() && !currenths->ports.hasOpenPorts())
          continue;

        xml_open_start_tag("host");
        xml_attribute("starttime", "%lu", (unsigned long) currenths->StartTime());
        xml_attribute("endtime", "%lu", (unsigned long) currenths->EndTime());
        xml_close_start_tag();
        write_host_header(currenths);
        printportoutput(currenths, &currenths->ports);
        printmacinfo(currenths);
        printosscanoutput(currenths);
        printserviceinfooutput(currenths);
#ifndef NOLUA
        printhostscriptresults(currenths);
#endif
        if (o.traceroute)
          printtraceroute(currenths);
        printtimes(currenths);
        log_write(LOG_PLAIN | LOG_MACHINE, "\n");
        xml_end_tag(); /* host */
        xml_newline();
      }
    }
    log_flush_all();

    o.numhosts_scanned += Targets.size();

    /* Free all of the Targets */
    while (!Targets.empty()) {
      currenths = Targets.back();
      delete currenths;
      Targets.pop_back();
    }
    o.numhosts_scanning = 0;
  } while (!o.max_ips_to_scan || o.max_ips_to_scan > o.numhosts_scanned);

#ifndef NOLUA
  if (o.script) {
    script_scan(Targets, SCRIPT_POST_SCAN);
    printscriptresults(script_scan_results, SCRIPT_POST_SCAN);
    while (!script_scan_results->empty()) {
      script_scan_results->front().clear();
      script_scan_results->pop_front();
    }
    delete new_targets;
    new_targets = NULL;
  }
#endif

  addrset_free(exclude_group);

  if (o.inputfd != NULL)
    fclose(o.inputfd);

  printdatafilepaths();

  printfinaloutput();

  free_scan_lists(&ports);

  eth_close_cached();

  if (o.release_memory) {
    nmap_free_mem();
  }
  return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章