ngx_http_access_handler

ngx_http_access_handler 1 定义ngx_http_access_handler 函数 定义在 ./nginx-1.24.0/src/http/modules/ngx_http_access_module.cstaticngx_int_tngx_http_access_handler(ngx_http_request_t*r){structsockaddr_in*sin;ngx_http_access_loc_conf_t*alcf;#if(NGX_HAVE_INET6)u_char*p;in_addr_taddr;structsockaddr_in6*sin6;#endifalcfngx_http_get_module_loc_conf(r,ngx_http_access_module);switch(r-connection-sockaddr-sa_family){caseAF_INET:if(alcf-rules){sin(structsockaddr_in*)r-connection-sockaddr;returnngx_http_access_inet(r,alcf,sin-sin_addr.s_addr);}break;#if(NGX_HAVE_INET6)caseAF_INET6:sin6(structsockaddr_in6*)r-connection-sockaddr;psin6-sin6_addr.s6_addr;if(alcf-rulesIN6_IS_ADDR_V4MAPPED(sin6-sin6_addr)){addrp[12]24;addrp[13]16;addrp[14]8;addrp[15];returnngx_http_access_inet(r,alcf,htonl(addr));}if(alcf-rules6){returnngx_http_access_inet6(r,alcf,p);}break;#endif#if(NGX_HAVE_UNIX_DOMAIN)caseAF_UNIX:if(alcf-rules_un){returnngx_http_access_unix(r,alcf);}break;#endif}returnNGX_DECLINED;}ngx_http_access_handler 函数是 ngx_http_access_module 在 NGX_HTTP_ACCESS_PHASE 阶段的处理函数 用于实现基于客户端 IP 地址的访问控制 它根据连接地址族IPv4、IPv6、UNIX 域套接字分发到对应的规则匹配函数 并返回允许、拒绝或不处理的调度结果。2 详解1 函数签名staticngx_int_tngx_http_access_handler(ngx_http_request_t*r)返回值 用于返回函数执行结果的状态码参数 ngx_http_request_t *r 指向当前 HTTP 请求上下文结构体2 逻辑流程1 局部变量 2 获取模块配置 3 根据地址族分别处理 4 默认返回1 局部变量{structsockaddr_in*sin;ngx_http_access_loc_conf_t*alcf;#if(NGX_HAVE_INET6)u_char*p;in_addr_taddr;structsockaddr_in6*sin6;#endif2 获取模块配置alcfngx_http_get_module_loc_conf(r,ngx_http_access_module);3 根据地址族分别处理switch(r-connection-sockaddr-sa_family){caseAF_INET:if(alcf-rules){sin(structsockaddr_in*)r-connection-sockaddr;returnngx_http_access_inet(r,alcf,sin-sin_addr.s_addr);}break;#if(NGX_HAVE_INET6)caseAF_INET6:sin6(structsockaddr_in6*)r-connection-sockaddr;psin6-sin6_addr.s6_addr;if(alcf-rulesIN6_IS_ADDR_V4MAPPED(sin6-sin6_addr)){addrp[12]24;addrp[13]16;addrp[14]8;addrp[15];returnngx_http_access_inet(r,alcf,htonl(addr));}if(alcf-rules6){returnngx_http_access_inet6(r,alcf,p);}break;#endif#if(NGX_HAVE_UNIX_DOMAIN)caseAF_UNIX:if(alcf-rules_un){returnngx_http_access_unix(r,alcf);}break;#endif}检查客户端连接的地址族 以决定调用哪个地址族的规则匹配函数case AF_INETIPv4 处理 case AF_INET客户端是 IPv4 连接。 if (alcf-rules) 仅当配置中存在 IPv4 规则才进行匹配。 若无规则则跳出最后返回 NGX_DECLINED。 ngx_http_access_inet(r, alcf, sin-sin_addr.s_addr) 调用 IPv4 规则匹配函数遍历 alcf-rules 链表 按顺序匹配 IP 或子网返回第一条命中的规则对应的状态码 若无匹配也返回 NGX_DECLINED。 该返回值直接作为本 handler 的返回值传递给访问阶段检查器。 意义将复杂的规则遍历和匹配逻辑封装到独立函数中保持 handler 的简洁性。case AF_INET6IPv6 处理条件编译处理 IPv4 映射的 IPv6 地址 检查该 IPv6 地址是否为 IPv4 映射地址 IN6_IS_ADDR_V4MAPPED(...) 系统宏检查该 IPv6 地址是否为 IPv4 映射地址格式如 ::ffff:192.168.1.1。 条件同时要求 alcf-rules 非空 只有配置了 IPv4 规则才有必要提取 IPv4 地址进行匹配。 提取 IPv4 地址 IPv4 映射地址的后 4 个字节p[12] ~ p[15]就是原始的 IPv4 地址网络字节序。 这里通过移位和加法在主机字节序中构造出 32 位整数 addr此时是网络字节序。 htonl(addr) 由于 addr 实际已经是网络字节序因为从网络数据直接拼出的 再调用 htonl 实际上是无操作在主机序与网络序相同的系统上 但这样写可以保证无论主机序如何传入 ngx_http_access_inet 的地址总是网络字节序 因为 ngx_http_access_inet 内部期望网络字节序且 htonl 将主机序转为网络序。 注意此处的 addr 是由网络字节序的字节拼接而来 存入主机变量时已经具有了网络字节序的值。 返回 直接返回 IPv4 规则匹配的结果 跳过后续的 IPv6 规则匹配 因为映射地址已经转换为 IPv4 进行处理。普通的 IPv6 规则匹配 调用 ngx_http_access_inet6 进行匹配传入原始 IPv6 地址 p。返回值直接传递。 如果没有配置 rules6则跳出 switch最终返回 NGX_DECLINED。 意义为纯 IPv6 连接提供了独立的规则匹配函数支持 IPv6 子网和地址规则。case AF_UNIXUNIX 域套接字处理条件编译 AF_UNIX 客户端是通过 UNIX 域套接字连接的通常用于本地通信。 if (alcf-rules_un) 如果配置了 UNIX 域套接字规则 调用 ngx_http_access_unix 进行匹配。 若没有规则则跳出。4 默认返回returnNGX_DECLINED;}如果之前所有的 case 都没有触发有效的规则匹配 即没有配置对应地址族的规则或规则列表为空 则执行此语句返回 NGX_DECLINED。 NGX_DECLINED 表示“本模块不处理此请求” 访问阶段检查器会忽略本模块继续调用下一个访问控制模块如果有 或在满足一定条件下放行。 保证在没有配置规则时模块透明地放行请求不影响服务器的正常工作。 同时这也与 Nginx 模块的约定一致 不处理的模块应返回 NGX_DECLINED把决定权交给阶段调度器。