nmap-1.51 源码解析 - 前言 && 端口的选择解析
字数 1672 2025-08-11 21:26:18

Nmap 1.51 源码解析:端口选择机制详解

1. 源码阅读目的与方法

1.1 阅读目的

  • 深入理解 Nmap 的核心扫描技术
  • 学习 Nmap 的编码风格和实现方式
  • 复用相关模块到自己的代码中

1.2 阅读方法

  • nmap.c 中的 main 函数开始顺序阅读
  • 以 Nmap 提供的参数为模块进行分解
  • 逐个实现小模块功能,逐步构建整体理解

2. 端口选择机制概述

Nmap 提供了两种主要的端口选择方式:

  1. 快速扫描模式 (-F 参数):从 /etc/services 文件中获取端口
  2. 自定义端口模式 (-p 参数):用户手动指定端口范围

重要限制-F-p 参数不能同时使用,否则会导致冲突。

3. 快速扫描模式 (-F 参数)

3.1 函数原型

unsigned short *getfastports(int tcpscan, int udpscan)

3.2 参数说明

  • tcpscan:是否进行 TCP 扫描
  • udpscan:是否进行 UDP 扫描

3.3 实现逻辑

  1. 打开 /etc/services 文件
  2. 逐行解析文件内容
  3. 根据协议类型(TCP/UDP)筛选端口
  4. 将选中的端口存入数组返回

3.4 关键代码解析

while(fgets(line, 80, fp)) {
    res = sscanf(line, "%*s %u/%s", &portno, proto);
    if (res == 2 && portno != 0 && portno != lastport) {
        lastport = portno;
        if (tcpscan && proto[0] == 't') 
            ports[portindex++] = portno;
        else if (udpscan && proto[0] == 'u') 
            ports[portindex++] = portno;
    }
}

3.5 特殊处理

  • TCP 端口:几乎获取所有 TCP 端口
  • UDP 端口:跳过同时支持 TCP 和 UDP 的端口(如 DNS 53 端口)

3.6 辅助函数

void *safe_malloc(int size) {
    void *mymem;
    if (size < 0) fatal("Tried to malloc negative amount of memmory!!!");
    if ((mymem = malloc(size)) == NULL) 
        fatal("Malloc Failed! Probably out of space.");
    return mymem;
}

4. 自定义端口模式 (-p 参数)

4.1 函数原型

unsigned short *getpts(char *origexpr)

4.2 支持的格式

  1. 单端口:-p8080
  2. 端口范围:-p200-1024
  3. 混合指定:-p8080,200-255
  4. 开放范围:-p60000-(表示60000-65535)

4.3 实现逻辑

  1. 去除输入字符串中的空格
  2. 按逗号分隔不同的端口指定
  3. 解析每个部分的端口范围
  4. 将选中的端口存入数组返回

4.4 关键代码解析

while((p = strchr(expr, ','))) {
    *p = '\0';
    if (*expr == '-') {
        start = 1;
        end = atoi(expr+1);
    } else {
        start = end = atoi(expr);
        if ((q = strchr(expr, '-')) && *(q+1)) {
            end = atoi(q+1);
        } else if (q && !*(q+1)) {
            end = 65535;
        }
    }
    // 添加端口到数组
    for(j=start; j <= end; j++) {
        ports[i++] = j;
    }
    expr = p + 1;
}

4.5 特殊处理

  • - 开头:表示从1到指定端口(如-100表示1-100)
  • - 结尾:表示从指定端口到65535(如60000-
  • 中间-:表示端口范围(如20-25

5. 实现对比

特性 getfastports (快速扫描) getpts (自定义端口)
数据来源 /etc/services 文件 用户输入
TCP 端口处理 获取几乎所有端口 精确获取指定范围
UDP 端口处理 跳过TCP/UDP共用端口 无特殊处理
性能考虑 优化UDP扫描速度 完全由用户控制
使用场景 快速扫描常见服务 精确扫描目标端口

6. 开发注意事项

  1. 内存管理:使用safe_malloc确保内存分配安全
  2. 错误处理:对非法输入进行严格检查
  3. 性能优化:避免重复端口和不必要的扫描
  4. 协议区分:正确处理TCP和UDP端口的不同需求

7. 历史背景

  • 早期版本中UDP扫描性能问题突出,因此设计了特殊的过滤逻辑
  • getpts函数命名源于getports名称已被占用
  • 开发者曾考虑使用负数表示UDP端口,但最终放弃该方案

8. 实际应用示例

8.1 快速扫描TCP端口

unsigned short *ports = getfastports(1, 0);

8.2 自定义端口扫描

unsigned short *ports = getpts("20-25,80,443,60000-");

8.3 完整流程

  1. 根据参数选择端口获取方式
  2. 调用相应函数获取端口数组
  3. 进行扫描操作
  4. 释放相关资源

9. 总结

Nmap 1.51 的端口选择机制体现了以下设计原则:

  1. 灵活性:提供自动和手动两种端口选择方式
  2. 实用性:针对不同协议优化扫描策略
  3. 健壮性:严格的输入验证和错误处理
  4. 高效性:优化内存使用和扫描效率

通过深入理解这些机制,可以更好地使用Nmap进行网络扫描,也能在自己的网络工具中借鉴这些优秀的设计思路。

Nmap 1.51 源码解析:端口选择机制详解 1. 源码阅读目的与方法 1.1 阅读目的 深入理解 Nmap 的核心扫描技术 学习 Nmap 的编码风格和实现方式 复用相关模块到自己的代码中 1.2 阅读方法 从 nmap.c 中的 main 函数开始顺序阅读 以 Nmap 提供的参数为模块进行分解 逐个实现小模块功能,逐步构建整体理解 2. 端口选择机制概述 Nmap 提供了两种主要的端口选择方式: 快速扫描模式 ( -F 参数):从 /etc/services 文件中获取端口 自定义端口模式 ( -p 参数):用户手动指定端口范围 重要限制 : -F 和 -p 参数不能同时使用,否则会导致冲突。 3. 快速扫描模式 ( -F 参数) 3.1 函数原型 3.2 参数说明 tcpscan :是否进行 TCP 扫描 udpscan :是否进行 UDP 扫描 3.3 实现逻辑 打开 /etc/services 文件 逐行解析文件内容 根据协议类型(TCP/UDP)筛选端口 将选中的端口存入数组返回 3.4 关键代码解析 3.5 特殊处理 TCP 端口 :几乎获取所有 TCP 端口 UDP 端口 :跳过同时支持 TCP 和 UDP 的端口(如 DNS 53 端口) 3.6 辅助函数 4. 自定义端口模式 ( -p 参数) 4.1 函数原型 4.2 支持的格式 单端口: -p8080 端口范围: -p200-1024 混合指定: -p8080,200-255 开放范围: -p60000- (表示60000-65535) 4.3 实现逻辑 去除输入字符串中的空格 按逗号分隔不同的端口指定 解析每个部分的端口范围 将选中的端口存入数组返回 4.4 关键代码解析 4.5 特殊处理 - 开头:表示从1到指定端口(如 -100 表示1-100) - 结尾:表示从指定端口到65535(如 60000- ) 中间 - :表示端口范围(如 20-25 ) 5. 实现对比 | 特性 | getfastports (快速扫描) | getpts (自定义端口) | |----------------|------------------------|--------------------| | 数据来源 | /etc/services 文件 | 用户输入 | | TCP 端口处理 | 获取几乎所有端口 | 精确获取指定范围 | | UDP 端口处理 | 跳过TCP/UDP共用端口 | 无特殊处理 | | 性能考虑 | 优化UDP扫描速度 | 完全由用户控制 | | 使用场景 | 快速扫描常见服务 | 精确扫描目标端口 | 6. 开发注意事项 内存管理 :使用 safe_malloc 确保内存分配安全 错误处理 :对非法输入进行严格检查 性能优化 :避免重复端口和不必要的扫描 协议区分 :正确处理TCP和UDP端口的不同需求 7. 历史背景 早期版本中UDP扫描性能问题突出,因此设计了特殊的过滤逻辑 getpts 函数命名源于 getports 名称已被占用 开发者曾考虑使用负数表示UDP端口,但最终放弃该方案 8. 实际应用示例 8.1 快速扫描TCP端口 8.2 自定义端口扫描 8.3 完整流程 根据参数选择端口获取方式 调用相应函数获取端口数组 进行扫描操作 释放相关资源 9. 总结 Nmap 1.51 的端口选择机制体现了以下设计原则: 灵活性 :提供自动和手动两种端口选择方式 实用性 :针对不同协议优化扫描策略 健壮性 :严格的输入验证和错误处理 高效性 :优化内存使用和扫描效率 通过深入理解这些机制,可以更好地使用Nmap进行网络扫描,也能在自己的网络工具中借鉴这些优秀的设计思路。