欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Nmap源码分析(整体架构)

程序员文章站 2022-07-14 11:25:36
...

整体架构

功能目录

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源码分析(整体架构)

主体程序位置在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;
}

 

相关标签: 文档