跳转至

rdns: NGINX HTTP rDNS 模块

安装

您可以在任何基于 RHEL 的发行版中安装此模块,包括但不限于:

  • RedHat Enterprise Linux 7、8、9 和 10
  • CentOS 7、8、9
  • AlmaLinux 8、9
  • Rocky Linux 8、9
  • Amazon Linux 2 和 Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-rdns
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-rdns

通过在 /etc/nginx/nginx.conf 顶部添加以下内容来启用该模块:

load_module modules/ngx_http_rdns_module.so;

本文档描述了 nginx-module-rdns v1.2.0,于 2026 年 2 月 2 日发布。


Test Build

NGINX 的反向 DNS 查找模块,具有基于主机名的访问控制。

对客户端 IP 地址执行异步反向 DNS (PTR) 查找,并使用解析的主机名进行访问控制决策、日志记录或条件请求处理。

特性

  • 异步 DNS 解析 - 使用 NGINX 的核心解析器进行非阻塞 PTR 查找
  • 双重验证模式 - 可选的正向 DNS 验证,以防止 DNS 欺骗
  • 基于正则表达式的访问控制 - 根据主机名模式允许或拒绝请求
  • 完整上下文支持 - 在 httpserverlocationif 块中工作
  • 高效缓存 - 利用 NGINX 的解析器缓存(最长可达 30 秒或 DNS TTL)
  • 动态模块支持 - 可构建为静态或动态模块
  • IPv4 和 IPv6 支持 - 适用于两种地址族

快速开始

http {
    # 定义一个 DNS 解析器(必需)
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    server {
        listen 80;

        location / {
            # 启用反向 DNS 查找
            rdns on;

            # 仅允许来自 *.google.com 的请求
            rdns_allow \.google\.com$;

            # 拒绝来自已知恶意行为者的请求
            rdns_deny \.spam\.example\.com$;

            # 在您的应用程序中使用主机名
            proxy_set_header X-Client-Hostname $rdns_hostname;
            proxy_pass http://backend;
        }
    }
}

指令

rdns

启用或禁用反向 DNS 查找。

语法 rdns on | off | double
默认 off
上下文 httpserverlocationif
阶段 rewrite

值:

描述
off 禁用 rDNS 查找。 $rdns_hostname 将为 -
on 执行单个 PTR 查找
double 执行 PTR 查找,然后通过正向 A/AAAA 查找进行验证

双重模式 通过验证解析的主机名是否指向原始客户端 IP 地址来防止 DNS 欺骗。如果验证失败,$rdns_hostname 被设置为 not found

rdns_allow

如果解析的主机名与模式匹配,则允许访问。

语法 rdns_allow regex
默认 -
上下文 httpserverlocation
阶段 access

该模式是一个不区分大小写的 PCRE 正则表达式。

rdns_deny

如果解析的主机名与模式匹配,则拒绝访问(返回 403)。

语法 rdns_deny regex
默认 -
上下文 httpserverlocation
阶段 access

该模式是一个不区分大小写的 PCRE 正则表达式。

变量

$rdns_hostname

包含反向 DNS 查找的结果。

意义
hostname 成功解析的主机名
not found 查找失败、超时或双重验证失败
- 在此上下文中禁用 rDNS

使用示例

验证搜索引擎爬虫

确保声称来自 Googlebot 的请求实际上来自 Google:

location / {
    resolver 8.8.8.8;

    # 仅对声称为 Googlebot 的请求执行 rDNS
    if ($http_user_agent ~* "Googlebot") {
        rdns double;
    }

    # 允许经过验证的 Googlebot
    rdns_allow \.googlebot\.com$;
    rdns_allow \.google\.com$;

    # 您的正常配置
    proxy_pass http://backend;
}

按主机名阻止请求

location / {
    resolver 8.8.8.8;
    rdns on;

    # 阻止已知的垃圾邮件来源
    rdns_deny \.spam\.example\.com$;
    rdns_deny \.malicious\.net$;

    proxy_pass http://backend;
}

记录客户端主机名

http {
    resolver 8.8.8.8;

    log_format with_hostname '$remote_addr - $rdns_hostname - $remote_user [$time_local] '
                             '"$request" $status $body_bytes_sent '
                             '"$http_referer" "$http_user_agent"';

    server {
        access_log /var/log/nginx/access.log with_hostname;

        location / {
            rdns on;
            proxy_pass http://backend;
        }
    }
}

基于主机名的条件逻辑

location / {
    resolver 8.8.8.8;
    rdns on;

    # 根据主机名设置变量
    set $is_internal "no";
    if ($rdns_hostname ~ \.internal\.company\.com$) {
        set $is_internal "yes";
    }

    # 在代理头中使用
    proxy_set_header X-Is-Internal $is_internal;
    proxy_set_header X-Client-Hostname $rdns_hostname;
    proxy_pass http://backend;
}

不同位置的不同规则

server {
    resolver 8.8.8.8;

    # 公共 API - 不使用 rDNS
    location /api/public {
        proxy_pass http://api-backend;
    }

    # 管理区域 - 严格的主机名验证
    location /admin {
        rdns double;
        rdns_allow \.admin\.company\.com$;
        proxy_pass http://admin-backend;
    }

    # 一般内容 - 记录主机名
    location / {
        rdns on;
        proxy_pass http://web-backend;
    }
}

访问控制行为

规则评估

  1. 规则按配置中出现的顺序进行评估
  2. 第一个匹配的规则决定结果:
  3. rdns_allow 匹配:请求被允许(继续处理)
  4. rdns_deny 匹配:请求被拒绝,返回 403 Forbidden
  5. 如果没有规则匹配,请求被允许

规则继承

  • 子上下文(位置)继承父上下文的规则,仅当它们没有定义自己的规则时
  • 一旦子上下文定义了任何 rdns_allowrdns_deny 规则,则不再继承父规则
server {
    rdns_allow \.trusted\.com$;  # 服务器级别规则

    location /public {
        # 继承服务器级别的 rdns_allow 规则
    }

    location /private {
        rdns_deny \.untrusted\.com$;  # 有自己的规则
        # 不继承服务器级别的 rdns_allow
    }
}

重要说明

解析器配置

在使用 rdns onrdns double 时,必须在相同上下文或父上下文中定义 resolver 指令。如果未满足此要求,NGINX 将无法启动,并显示错误 no core resolver defined for rdns

## 正确:定义了解析器
server {
    resolver 8.8.8.8;
    location / {
        rdns on;  # 工作正常
    }
}

## 错误:没有解析器
server {
    location / {
        rdns on;  # 错误:没有定义核心解析器
    }
}

有问题的配置

server { rdns on;

location / {
    error_page 404 = @fallback;
}

location @fallback {
    # 循环!rDNS 查找重新启动请求处理
}

}

修复后的配置

server { rdns on;

location / {
    error_page 404 = @fallback;
}

location @fallback {
    rdns off;  # 在命名位置禁用 rDNS
    # ...
}

} ```

性能考虑

  • 每次 rDNS 查找都会增加请求处理的延迟
  • 使用条件启用(通过 if 块)将查找限制为特定用户代理或条件
  • 解析器缓存有助于减少对同一 IP 的重复查找
  • 仅在需要防止欺骗时考虑使用 double 模式

故障排除

"no core resolver defined for rdns"

在相同或父上下文中添加 resolver 指令: nginx resolver 8.8.8.8;

$rdns_hostname 始终为 "not found"

  1. 验证解析器是否可以从您的服务器访问
  2. 检查解析器超时设置
  3. 如果使用 rdns double,确保 PTR 记录的主机名有一个有效的 A/AAAA 记录指向客户端 IP
  4. 检查 NGINX 错误日志以获取解析器错误

$rdns_hostname 始终为 "-"

rdns 指令要么: - 在当前上下文中未启用 - 设置为 off - 在条件为假的 if 块中

403 Forbidden 响应

一个 rdns_deny 规则匹配了客户端的主机名。检查您的拒绝模式和实际解析的主机名。

GitHub

您可以在 nginx-module-rdns 的 GitHub 仓库 中找到有关此模块的其他配置提示和文档。