You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C编写的Nginx模块中获取服务器静态IP?

问题背景

我有一台监听0.0.0.0的Nginx反向代理服务器,server_name为feng.cc:8080,核心配置如下:

upstream ssl-proxy {
    server 172.16.43.210:5000;
}

server {
    listen 0.0.0.0:8080;
    server_name feng.cc:8080;

    location / {
        proxy_pass  http://ssl-proxy/;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  Host  $http_host;
        proxy_set_header Connection "";
    }
}

服务器静态IP为172.16.39.52,feng.cc是hosts文件中映射到该IP的自定义域名。

我在编写Nginx C模块时,尝试通过ngx_http_request_s结构体的r->connection->local_sockaddr、r->connection->listening等字段获取服务器静态IP,但返回的都是0.0.0.0。不过观察到Nginx与上游服务器通信时确实使用的是静态IP172.16.39.52(tcpdump结果如下):

$ hostname -I
172.16.39.52

$ tcpdump -nn -iany dst port 5000
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [S], seq 3565149610, win 32120, options [mss 1460,sackOK,TS val 1811543954 ecr 0,nop,wscale 7], length 0
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [.], ack 515140155, win 251, options [nop,nop,TS val 1811543955 ecr 2228136305], length 0
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [P.], seq 0:139, ack 1, win 251, options [nop,nop,TS val 1811543955 ecr 2228136305], length 139
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [.], ack 174, win 250, options [nop,nop,TS val 1811543957 ecr 2228136307], length 0
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [.], ack 203, win 250, options [nop,nop,TS val 1811543957 ecr 2228136307], length 0
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [F.], seq 139, ack 203, win 250, options [nop,nop,TS val 1811543958 ecr 2228136307], length 0
eth0  Out IP 172.16.39.52.26130 > 172.16.43.210.5000: Flags [.], ack 204, win 250, options [nop,nop,TS val 1811543959 ecr 2228136309], length 0

请问有没有办法在Nginx C模块中获取服务器的静态IP?


解决方案

方法1:解析本地网卡信息(直接获取系统静态IP)

调用系统API遍历网卡接口,筛选出非回环、处于UP状态的目标网卡IP。适合需要独立于Nginx连接状态获取IP的场景。

示例代码片段:

#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>

ngx_str_t get_local_static_ip(ngx_pool_t *pool) {
    ngx_str_t ip = ngx_null_string;
    struct ifaddrs *ifap, *ifa;
    struct sockaddr_in *sa;

    if (getifaddrs(&ifap) != 0) {
        return ip;
    }

    for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL || ifa->ifa_flags & IFF_LOOPBACK) {
            continue;
        }

        if (ifa->ifa_addr->sa_family == AF_INET) {
            sa = (struct sockaddr_in *) ifa->ifa_addr;
            // 按网卡名称过滤,比如目标网卡是eth0
            if (ngx_strcmp((u_char *)ifa->ifa_name, (u_char *)"eth0") == 0) {
                u_char *ip_str = inet_ntoa(sa->sin_addr);
                ip.len = ngx_strlen(ip_str);
                ip.data = ngx_palloc(pool, ip.len + 1);
                if (ip.data == NULL) {
                    break;
                }
                ngx_memcpy(ip.data, ip_str, ip.len);
                ip.data[ip.len] = '\0';
                break;
            }
        }
    }

    freeifaddrs(ifap);
    return ip;
}

方法2:利用上游连接信息获取出口IP

当Nginx与上游建立连接时,会使用系统路由选择的出口IP(即静态IP)。可以在模块中拦截上游连接事件,从上游连接的sockaddr中提取实际通信的IP。

示例思路代码:

// 在处理上游请求的回调逻辑中
if (r->upstream && r->upstream->peer && r->upstream->peer->connection) {
    ngx_connection_t *upstream_conn = r->upstream->peer->connection;
    if (upstream_conn->local_sockaddr->sa_family == AF_INET) {
        struct sockaddr_in *sa = (struct sockaddr_in *) upstream_conn->local_sockaddr;
        u_char *ip_str = inet_ntoa(sa->sin_addr);
        // 将ip_str转换为ngx_str_t使用
    }
}

注意:该方法仅在Nginx与上游已建立连接后生效,适合和上游通信强相关的场景。

方法3:配置文件显式指定,模块读取配置

在Nginx配置中添加自定义配置项,直接指定静态IP,模块读取该配置值。这种方法简单可控,适合静态IP固定的场景。

  1. 配置文件中添加自定义项:
server {
    listen 0.0.0.0:8080;
    server_name feng.cc:8080;
    # 自定义静态IP配置
    local_static_ip 172.16.39.52;

    location / {
        # 原有配置...
    }
}
  1. 模块中实现配置读取:
// 定义配置结构体
typedef struct {
    ngx_str_t local_static_ip;
} ngx_http_my_module_loc_conf_t;

// 配置解析回调
static char *ngx_http_my_module_set_static_ip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
    ngx_http_my_module_loc_conf_t *mlcf = conf;
    ngx_str_t *value = cf->args->elts;

    mlcf->local_static_ip = value[1];
    return NGX_CONF_OK;
}

// 注册配置命令
static ngx_command_t ngx_http_my_module_commands[] = {
    {
        ngx_string("local_static_ip"),
        NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
        ngx_http_my_module_set_static_ip,
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_my_module_loc_conf_t, local_static_ip),
        NULL
    },
    ngx_null_command
};

// 请求处理中获取配置
static ngx_int_t ngx_http_my_module_handler(ngx_http_request_t *r) {
    ngx_http_my_module_loc_conf_t *mlcf = ngx_http_get_module_loc_conf(r, ngx_http_my_module);
    ngx_str_t static_ip = mlcf->local_static_ip;
    // 使用static_ip进行业务逻辑
    return NGX_OK;
}

内容的提问来源于stack exchange,提问作者hartvon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:54:55