资讯动态

Nixpkgs 中 /etc 运行时文件的可靠供给:iana-etc、`NIX_ETC_*` 环境变量与 glibc 补丁原理

发布时间:2026/9/18 11:36:07 来源:尧图企业网站定制
Nixpkgs 中 /etc 运行时文件的可靠供给iana-etc、NIX_ETC_*环境变量与 glibc 补丁原理【免费下载链接】nixpkgsNix Packages collection NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgsglibc 的部分函数如getprotobyname在运行时需要读取/etc目录下的系统数据文件如/etc/protocols、/etc/services。在 Nixpkgs 的纯函数式构建环境下这些文件默认并不存在直接依赖它们会导致构建或运行结果不可复现。本文以 doc/packages/etc-files.section.md 为核心结合仓库内iana-etc包的实现、glibc 的nix-nss-open-files.patch补丁以及 NixOS 的environment.etc配置完整讲解 Nixpkgs 如何通过NIX_ETC_PROTOCOLS/NIX_ETC_SERVICES环境变量机制为 glibc 提供确定性的/etc数据文件。读完本文你将掌握这一机制的完整调用链并能在自己的buildInputs或 NixOS 配置中正确使用它。问题背景glibc 对/etc运行时文件的依赖glibc 的某些 NSSName Service Switch调用需要访问运行时数据文件。典型的例子包括/etc/protocolsIP 协议号与协议名的映射如tcp→ 6、udp→ 17/etc/servicesTCP/UDP 端口号与知名服务名的映射如http→ 80/tcp。以getprotobyname这类函数为例它们由 glibc 的nss_files模块实现底层通过文件数据库读取上述数据。在传统发行版上这些文件通常由发行版自带的包提供例如 Debian 系的netbase包并且一般默认已预装在系统中。正是这种系统默认存在的假设带来了可复现性问题如果你的代码依赖这些文件恰好存在于构建或运行环境中那么换一台机器、换一个发行版、甚至换一个容器基础镜像结果就可能不同——因为这些文件的来源、内容和存在与否都不受你控制。对于追求确定性构建的 Nix/NixOS 生态来说这是必须解决的问题。解决方案iana-etc 包与NIX_ETC_*环境变量Nixpkgs 的解决办法是将这两份数据文件打包成纯函数式派生derivation并通过 setup hook 以环境变量的方式注入到使用者的构建/运行环境中。具体机制如下如果你的包把iana-etc放进buildInputs那么iana-etc提供的 setup hook 会在该环境下自动设置两个环境变量NIX_ETC_PROTOCOLS→ 指向包内/etc/protocols文件NIX_ETC_SERVICES→ 指向包内/etc/services文件。由于 Nix 构建环境的纯净性这两个环境变量指向的是/nix/store中经过哈希校验的路径因此内容是确定性的、可复现的。仓库中的包定义当前仓库中iana-etc的定义位于 pkgs/by-name/ia/iana-etc/package.nix其核心逻辑非常简洁stdenvNoCC.mkDerivation rec { pname iana-etc; version 20251215; src fetchzip { url https://github.com/Mic92/iana-etc/releases/download/${version}/iana-etc-${version}.tar.gz; sha256 sha256-BUGhVHvWSdFJdqaoPasLt87lTUFVF2B7X7sfigwrJss; }; installPhase install -D -m0644 -t $out/etc services protocols ; setupHook writeText setup-hook export NIX_ETC_PROTOCOLSout/etc/protocols export NIX_ETC_SERVICESout/etc/services ; meta { homepage https://github.com/Mic92/iana-etc; description IANA protocol and port number assignments (/etc/protocols and /etc/services); platforms lib.platforms.unix; license lib.licenses.mit; }; }值得注意的实现细节使用stdenvNoCC无编译器的最小 stdenv因为这里只是搬运数据文件无需任何编译工具链installPhase把数据源中的services与protocols两个文件以0644权限安装到$out/etc下与它们在真实系统/etc中的路径保持一致setupHook通过writeText内联生成 setup hook 脚本脚本中的out在构建时会被替换为输出的 store 路径从而让环境变量始终指向该包的确切输出该包被声明为lib.platforms.unix平台可用许可证为 MIT。实际验证nix-shell 中的效果原文档给出了一个最直接的验证方式——进入包含iana-etc的 shell 后直接检查环境变量 nix-shell -p iana-etc [nix-shell:~]$ env | grep NIX_ETC NIX_ETC_SERVICES/nix/store/aj866hr8fad8flnggwdhrldm0g799ccz-iana-etc-20210225/etc/services NIX_ETC_PROTOCOLS/nix/store/aj866hr8fad8flnggwdhrldm0g799ccz-iana-etc-20210225/etc/protocols注意示例中的 store 路径对应的是当时 20210225 版本的iana-etc当前仓库中该包版本已更新为 20251215见 package.nix实际路径会随 store 哈希变化但机制完全一致。在你自己构建的项目中若把iana-etc加入buildInputs构建阶段的环境同样会包含这两个变量从而让 glibc 的 NSS 文件数据库调用获得确定性的数据来源。底层原理glibc 补丁如何读取环境变量环境变量设置好了glibc 又是如何感知它们的答案在 glibc 的 NSS 文件数据库实现中。Nixpkgs 对上游 glibc 打了一个专门的补丁pkgs/development/libraries/glibc/nix-nss-open-files.patch。该补丁修改了三个文件工作方式如下在nss/nss_files/files-proto.c中为 protocols 数据库定义环境变量名#define NIX_DATAFILE NIX_ETC_PROTOCOLS在nss/nss_files/files-service.c中为 services 数据库定义环境变量名#define NIX_DATAFILE NIX_ETC_SERVICES在共享的nss/nss_files/files-XXX.c的internal_setent中打开数据文件前先检查环境变量#ifdef NIX_DATAFILE // use the Nix environment variable such as NIX_ETC_PROTOCOLS char *path secure_getenv (NIX_DATAFILE); // if the environment variable is set, then read from the /nix/store entry instead if (path path[0]) { file path; } #endif *stream __nss_files_fopen (file);这里有两个值得注意的工程细节优先使用环境变量缺省回退/etc当NIX_ETC_*被设置且非空时glibc 改从/nix/store下的确定性路径读取数据如果未设置例如传统发行版上的常规 glibc 使用场景则仍按原逻辑从/etc的默认位置读取。这正是原文档所述行为的源码级实现。使用secure_getenv而非getenvsecure_getenv在 setuid/setgid 程序中会返回 NULL避免特权程序受环境变量注入影响这是一个安全敏感的正确选择——因为NSS_DECLARE_MODULE_FUNCTIONS (files)生成的 NSS 模块会被包括getprotobyname、getservbyname等在内的系统调用链所使用。NixOS 系统层面environment.etc 的接线上述机制解决的是构建/开发环境中没有/etc文件的问题。而在一个完整的 NixOS 系统中/etc/protocols与/etc/services又从哪里来答案同样是iana-etc。在 nixos/modules/config/networking.nix 中NixOS 默认通过environment.etc把这些文件合入系统/etcenvironment.etc { # /etc/services: TCP/UDP port assignments. services.source pkgs.iana-etc /etc/services; # /etc/protocols: IP protocol numbers. protocols.source pkgs.iana-etc /etc/protocols; ... };由此可以总结出 Nixpkgs 处理/etc运行时文件的两条互补路径场景数据来源机制非 NixOS 的构建/运行环境iana-etc的 store 输出setup hook 设置NIX_ETC_PROTOCOLS/NIX_ETC_SERVICESglibc 补丁通过secure_getenv读取NixOS 系统iana-etc的 store 输出environment.etc将其符号链接进系统/etc/services、/etc/protocols两条路径最终都指向同一个数据源——iana-etc包中由 IANA 官方分配数据生成的services与protocols文件从而保证了从源码、构建产物到运行系统的全链路一致性。如果你开发的包需要在构建或运行时使用协议号/端口号查询把iana-etc加入buildInputs即可获得与 NixOS 系统完全一致、且可复现的数据环境。【免费下载链接】nixpkgsNix Packages collection NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价