
简介在离线或内网环境中编译安装libpcap数据包捕获库经常因为缺少gcc、m4、bison、flex等基础工具链而中途失败。资源包将上述全部依赖与libpcap源码打包并提供自动化安装脚本面向Linux系统管理员、网络运维人员以及安全测试工程师目标是让用户在无外网条件下也能一次性完成环境部署。libpcap是Unix/Linux平台经典的网络数据包捕获函数库支持原始数据包捕获、自定义数据包发送、流量采集统计以及灵活的规则过滤可广泛应用于网络监控、协议分析、网络故障排查和安全工具开发等场景。整个资源包共2个文件一个tar包内整合了gcc-4.8.5、m4-1.4.19、bison-3.7.6、flex-2.6.4和libpcap-1.10.1的完整源码另一个是自动安装脚本压缩后总大小约43.29MB用户执行脚本即可自动完成依赖检测、编译、安装及环境变量配置免去手动逐一下载源码、解决依赖顺序和编译报错的繁琐过程大幅提升部署效率与成功率。目前已有1037人学习下载特别适合需要快速搭建抓包开发环境并希望避开踩坑环节的中高级Linux使用者。1. 离线编译 libpcap 到底难在哪依赖不是只有 gcc、m4、bison、flex 这四件套看到「libpcap离线脚本自动安装含全部依赖gcc,m4,bison,flex,libpcap」这个需求的人大概率和我一样机器在内网没有外网 yum 源apt 连不上手里只有一个 tar 包列表却要在这台机器上把抓包库装出来。libpcap 本身不难编译难的是它背后的工具链configure 要找到 flex 和 bison缺了它们哪怕源码包里预生成了 scanner.c 和 grammar.cmake 也会因为时间戳规则去重新生成然后直接报错。更隐蔽的是gcc 和系统头文件是否完整往往要等到 make 跑到一半才暴露那正是离线安装最怕的局面日志刷了一大屏才发现第一步就错了。这篇文章我按自己的实操顺序来写先理清依赖关系再准备离线物料然后给一套可以直接改的脚本最后是你迟早会碰到的几个坑。如果你正打算在内网或信创环境里装 libpcap这篇文章能帮你省掉至少一次「装到一半推倒重来」的经历。2. 先盘清楚依赖关系libpcap 为什么绕不开 flex、bison以及 gcc 的边界2.1 libpcap 编译链里的三个角色configure、scanner 和 grammarlibpcap 不是一个「解压就能 make」的纯 C 项目。它内部有一份词法文件 scanner.l 和一份语法文件 grammar.y分别用来解析 pcap 过滤表达式比如你写tcp port 80这类 BPF 语法时真正干活的就是这两个文件生成的代码。flex 负责把 scanner.l 翻译成 scanner.cbison 负责把 grammar.y 翻译成 grammar.c这两个生成文件会被编进 libpcap.so 里。有人会问官方发布包里不是已经带了生成好的 .c 文件吗这是对的release tar 里确实带了。但 makefile 里写了依赖规则只要 scanner.l 或 grammar.y 的时间戳比对应的 .c 文件新make 就会强制调用 flex / bison 重新生成。离线环境下你从 U 盘拷文件时间戳经常乱掉或者你改过一行语法文件都会触发重新生成。所以「包里带了为什么还要装 flex/bison」这个问题的答案很简单不装也能赌一把但一旦触发重新生成configure 阶段埋下的雷就炸了。这里还要澄清一个词义混淆标题里的 flex 是 GNU Flex词法分析器生成器不是前端里的 CSS Flex 布局m4 是 GNU m4 宏处理器也不是 Apple M4 芯片。搜索引擎里这两个词的热度高但和本场景完全无关别下错包。2.2 gcc、make、头文件的边界不是所有机器都自带完整工具链很多内网机器上面有/usr/bin/gcc你以为工具链是齐的一编译却发现stdio.h: No such file or directory。这是 gcc 可执行文件和 glibc 头文件分离导致的gcc 只是个驱动真正干活需要 cc1、libc.so、以及 /usr/include 下的一整套头文件。在 Red Hat 系里这些由glibc-devel提供在 Debian 系里由libc6-dev提供。离线环境里缺这一层比缺 gcc 还常见。真正的离线难点在 gcc 本身。如果机器上完全没有 gcc你有两条路第一条是从同版本操作系统的 ISO 里取 gcc 的 rpm/deb 包用yum localinstall或dpkg -i装上这是最省事的第二条是源码编译 gcc但 gcc 源码编译要用make bootstrap等于先用系统里的老编译器把 gcc 编译一遍再用新 gcc 把自己重新编一遍耗时按小时算。所以我在脚本里对 gcc 的策略是「优先本地源补源码编译兜底」而不是一上来就硬编。另外别忘了 make 本身。有的最小化安装里连 make 都没有这个必须跟着 gcc 一起补否则后面每一步都跑不动。2.3 安装顺序与版本约束m4 → bison → flex → libpcap依赖顺序是硬约束不能乱。m4 是 bison 的依赖bison 是 flex 的依赖flex 和 bison 又是 libpcap 的依赖。所以正确顺序是组件安装顺序被谁依赖离线安装要点m41bison、flex无前置依赖configure 后直接 makebison2flex需要 m4 已装且可用否则 configure 报错flex3libpcap需要 bison 和 m4生成的 scanner.c 要能被编译器读libpcap4用户程序configure 会同时探测 flex 和 bison缺一不可版本上我给不出「必须哪个版本」的绝对结论因为不同发行版打包的 flex/bison 差异很大。但有一条实测规律flex 不要用 2.5.x 那种古董2.6.x 系列更稳bison 太新比如 3.8生成的 grammar.c 默认要求编译器支持 C99如果你的 gcc 比较老需要给 CFLAGS 加-stdc99。我一般把这四个包按相对宽松的版本组合来准备m4 1.4.19 附近、bison 3.7 左右、flex 2.6.4 左右、libpcap 1.10.x。版本不必完全一致但尽量别跨代太多。另一个容易被忽略的是 prefix 统一。四个依赖如果装到不同目录后面 libpcap 的 configure 可能找不到 flex 命令也可能链接时找不到 libm4 相关的库。我的习惯是统一装到/usr/local脚本里用PREFIX/usr/local贯穿全程。3. 离线物料准备把四个依赖加 libpcap 整理成可复用的 pkg 目录3.1 从有网机器下载源码包到 src-pkg 为止不碰在线安装离线安装的物料准备本质上是在一台有网机器上完成下载再通过内网传过去。下载时我建议只认官方 release 页面或者公司内网搭好的镜像站。文件名要统一带版本号比如m4-1.4.19.tar.xz、bison-3.7.6.tar.xz、flex-2.6.4.tar.gz、libpcap-1.10.4.tar.gz这样脚本里好匹配也方便对 sha256。下载之后不要急着传先做两件事。第一件sha256sum算一遍校验值写进一个 manifest.txt传到内网后先比对再解压。第二件确认 tar 包能完整解开有的下载工具会在断点时留一个残缺包解压时tar: Unexpected EOF in file才暴露等到内网才发现等于白跑一趟。我通常在下载机本地先tar -tf看一眼文件列表能跑通再打包传输。这里要强调一下不要在标题里写「含全部依赖」就真的以为只有这五个包。libpcap 的 configure 还会检查libnl之类的可选依赖但基础编译用不到可以不管。真正必须齐的是gcc、make、glibc-devel/libc6-dev、m4、bison、flex、libpcap。前三个和编译器相关后四个是标题里明确列出的一个都不能少。3.2 利用系统 ISO 构建本地 yum/apt 源快速补齐 gcc 的另一种路径如果你手头有目标机器同版本操作系统的安装 ISO那是补 gcc 最快的方式。这一步很多新手会卡住因为yum install gcc会去连外网镜像内网里直接超时。但你把 ISO 挂载成本地源yum 就只认本地文件。以 CentOS 7 为例mkdir -p /mnt/cdrom mount -o loop /path/to/CentOS-7-x86_64-Minimal.iso /mnt/cdrom # 创建本地源 repo 文件 cat /etc/yum.repos.d/local.repo EOF [local] namelocal iso repo baseurlfile:///mnt/cdrom enabled1 gpgcheck0 EOF # 清缓存后只从本地源装 yum clean all yum --disablerepo* --enablerepolocal install -y gcc gcc-c make glibc-devel这段脚本里--disablerepo* --enablerepolocal是关键参数它把一切外部仓库全部禁用只允许 local 源避免 yum 因为网络超时卡在原地。装完gcc --version确认版本。Debian/Ubuntu 系把 ISO 里的 pool 目录做成 apt 源也可以但流程更绕我的建议是内网环境优先用 RPM 系物料好凑。如果你连 ISO 都没有只能源码编译 gcc那我建议把 gcc 源码编译单独跑别和 m4/bison/flex 混在一个脚本里。因为 gcc 的 configure 参数多--disable-multilib、--enable-languagesc,c都得按平台调放进一个通用脚本里反而容易翻车。3.3 目录规划脚本认准 SRC_DIR 与 PREFIX别把源码散在 /root 下离线装依赖最容易乱的环节就是路径。我见过同事把 flex 源码解压到/root/download/flex-2.6.4libpcap 又放到另一个目录最后 configure 找不到 flex排查时每个目录翻一遍。规范做法是建三个目录SRC_DIR所有源码包统一解压到这里命名统一为/opt/offline/src/名字-版本PREFIX安装目标统一/usr/localLOG_DIR所有编译日志输出到这里命名/opt/offline/logs/名字.log目录规划看起来是小事但脚本越复杂越依赖这个约定。我在下一章的脚本里会用这三个变量贯穿全部流程你拿到手后只要改SRC_DIR和PREFIX两个变量就能适配自己的机器。把源码和日志分开还有个额外好处编译失败后看日志不会污染源码目录重新 make clean 也不会误删日志。4. 自动安装脚本从环境探测到 make install 的完整 bash 实现4.1 主脚本 install_pcap_offline.shlog、探测、编译三件事下面这版脚本是我常用的模板按标题里的五个组件逐个处理。它不追求把每个 configure 参数写全而是把「先探测、再编译、日志留底」这三个动作做扎实#!/bin/bash # install_pcap_offline.sh # 离线安装 m4/bison/flex/libpcapgcc 优先本地源源码编译兜底 set -uo pipefail SRC_DIR${SRC_DIR:-/opt/offline/src} PREFIX${PREFIX:-/usr/local} LOG_DIR${LOG_DIR:-/opt/offline/logs} PKG_ORDERm4 bison flex libpcap mkdir -p $SRC_DIR $LOG_DIR log() { echo [$(date %F %T)] $* | tee -a $LOG_DIR/install.log } die() { log FATAL: $* exit 1 } # 探测某个包是否已可用避免重复编译 pkg_exists() { case $1 in m4) command -v m4 /dev/null 21 ;; bison) command -v bison /dev/null 21 ;; flex) command -v flex /dev/null 21 ;; libpcap) test -f $PREFIX/lib/libpcap.so || test -f $PREFIX/lib64/libpcap.so ;; esac } build_one() { local pkg$1 local src_dir$SRC_DIR/$pkg [ -d $src_dir ] || die 源码目录不存在: $src_dir cd $src_dir log 开始编译 $pkg ./configure --prefix$PREFIX $LOG_DIR/$pkg.log 21 \ || die $pkg configure 失败见 $LOG_DIR/$pkg.log make -j$(nproc) $LOG_DIR/$pkg.log 21 \ || die $pkg make 失败见 $LOG_DIR/$pkg.log make install $LOG_DIR/$pkg.log 21 \ || die $pkg make install 失败见 $LOG_DIR/$pkg.log log $pkg 已安装到 $PREFIX } # 第一步保证 gcc/make 存在优先本地 yum 源 if ! command -v gcc /dev/null 21 || ! command -v make /dev/null 21; then log 编译工具链不完整尝试从本地 yum 源补齐 if command -v yum /dev/null 21; then yum --disablerepo* --enablerepolocal install -y \ gcc gcc-c make glibc-devel $LOG_DIR/gcc.log 21 \ || log 本地源安装 gcc 失败后续走源码编译 fi if ! command -v gcc /dev/null 21; then build_one gcc fi fi # 第二步按依赖顺序装 m4/bison/flex/libpcap for pkg in $PKG_ORDER; do if pkg_exists $pkg; then log $pkg 已存在跳过 continue fi build_one $pkg done # 第三步libpcap 的 configure 集中处理FLAGS 统一传 cd $SRC_DIR/libpcap || die 找不到 libpcap 源码目录 ./configure \ --prefix$PREFIX \ --enable-shared \ --enable-static \ $LOG_DIR/libpcap.log 21 || die libpcap configure 失败 make -j$(nproc) $LOG_DIR/libpcap.log 21 || die libpcap make 失败 make install $LOG_DIR/libpcap.log 21 || die libpcap make install 失败 # 第四步刷新动态库缓存并把 bin 加入 PATH echo $PREFIX/lib /etc/ld.so.conf.d/pcap-offline.conf ldconfig export PATH$PREFIX/bin:$PATH log 安装流程结束脚本里set -uo pipefail故意不写set -e这是踩坑之后的取舍离线编译时某个组件安好了但探测命令返回值诡异一旦用了set -e脚本会在最莫名其妙的地方退出连日志都不留。我用die来做显式退出每个失败点都能往日志里写一行明确信息。pkg_exists函数里对 libpcap 做了lib和lib64两种路径探测因为 64 位系统上/usr/local/lib64也常见少探一个就会重复编译一次。4.2 configure 参数与 make 日志的处理把「gcc 日志输出到文件」变成习惯前面脚本里每个编译步骤都带了 $LOG_DIR/$pkg.log 21这是我在线上环境养成的铁律编译日志一律输出到文件而不是直接打到终端。原因有两个一是离线服务器上你开的终端经常因为 SSH 超时断掉日志打到标准输出就丢了二是 make 的输出量大终端刷屏后根本找不到真正的错误行但写进文件就能随时精准搜索。具体搜索方法很固定。编译失败后先看配置阶段是否通过grep -nE error:|Error [0-9]|undefined reference|No such file \ /opt/offline/logs/libpcap.log | head -n 30error:覆盖 gcc 的常规编译错误undefined reference是链接期问题No such file多半是头文件路径缺失。这三类特征基本能定位九成以上的失败原因。如果你的日志里什么都没有再看文件末尾tail -n 50 /opt/offline/logs/libpcap.log我自己的习惯是失败后不急着重跑先看最后 50 行再往前翻 200 行确认是 configure 阶段挂的、make 阶段挂的、还是 make install 阶段挂的。三个阶段对应的解决手段完全不同configure 失败查依赖和 prefixmake 失败查编译器参数和头文件make install 失败查权限和目录。4.3 libpcap 的安装与头文件对齐--prefix 要贯穿所有依赖脚本后半段单独拎出了 libpcap 的 configure因为它是整个流程的终点参数比前面的依赖更关键。--enable-shared和--enable-static我一般都同时开因为内网环境里你不知道后续的应用是动态链接还是静态链接。比如用 libpcap 静态编 tcpdump没开--enable-static就会在链接时报libpcap.a: cannot open shared object file。另一个对齐问题是头文件路径。m4、bison、flex 装到/usr/local后libpcap 的 configure 默认会在/usr/local/include和/usr/local/lib里找依赖。但如果你的 PREFIX 改成了/opt/toolslibpcap 的 configure 可能探测不到 flex这时要补环境变量export PATH/opt/tools/bin:$PATH export LDFLAGS-L/opt/tools/lib export CPPFLAGS-I/opt/tools/include export PKG_CONFIG_PATH/opt/tools/lib/pkgconfig我把 PKG_CONFIG_PATH 单独列出来是因为很多人只记得 PATH漏了 pkg-config 的搜索路径。libpcap 的 configure 对 flex、bison 的探测用的是AC_PATH_PROGPATH 不指过去就找不到但对其他可选库的探测走 pkg-configPKG_CONFIG_PATH 不指过去就链接不上。两个变量一个管「找命令」一个管「找库」缺哪个都有问题。5. 离线安装避坑5 条日志里常见但脚本容易漏掉的坑5.1 configure 一直报 “checking for lex... no”但 flex 明明已经解压了现象libpcap 的 configure 输出里checking for lex... no后面跟着checking for flex... no但ls看源码目录里 flex-2.6.4 就在那里。原因flex 源码只是解压了并没有编译安装。很多人把「解压源码包」和「安装成功」混为一谈configure 是在/usr/local/bin里找 lex/flex 可执行文件找不到自然不会因为你解压了源码就通过。解决先执行上一章的build_one flex确认/usr/local/bin/flex存在后再回来跑 libpcap 的 configure。如果 flex 装了还是报 no用command -v flex看 PATH 里有没有/usr/local/bin没有就export PATH/usr/local/bin:$PATH。这里最容易忽略的是 bison 同理checking for yacc... no八成是 bison 没装或没进 PATH而不是 configure 出 bug。5.2 make 报 “stdio.h: No such file”问题不在 gcc 而在 glibc-devel现象libpcap 编译到某个 .c 文件时提示stdio.h: No such file or directorygcc 版本也正常gcc --version能输出。原因gcc 可执行文件在但系统没装 C 标准库的头文件。在 CentOS 7 上对应glibc-devel在 Ubuntu 上对应libc6-dev。最小化安装的机器经常缺这个内网里又没有在线源所以它比 gcc 缺失更隐蔽。解决回到第 3 章的 ISO 本地源把glibc-devel一起装掉。如果你已经在跑脚本把第 4 章 yum 安装那行的包列表从gcc gcc-c make扩成gcc gcc-c make glibc-devel并且把gcc的探测条件改成同时检查/usr/include/stdio.hif ! command -v gcc /dev/null 21 || [ ! -f /usr/include/stdio.h ]; then # 补齐工具链或源码编译 fi5.3 gcc -v 升级后还是旧版本PATH 与动态库的双重门现象源码编译完新版 gcc 装到/usr/local/bin执行gcc --version却还是系统自带的 4.8.5或者显示是新版本但编译出来的程序运行时提示找不到libstdc.so.6。原因/usr/bin在 PATH 里排在/usr/local/bin前面shell 直接命中了老 gcc就算你改了 PATH新版 gcc 编译出的程序依赖的新版 libstdc 也装在了/usr/local/lib64而系统 loader 默认不去那里找。解决用update-alternatives或直接改 PATH 顺序。前者是 RPM 系的标准做法update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc 100 update-alternatives --config gcc后者是确认/usr/local/bin在 PATH 最前面。动态库层面检查/etc/ld.so.conf.d/下有没有包含/usr/local/lib64没有就建一个并执行ldconfig。验证时不要只看gcc --version还要编一个小程序或直接跑ldd看链接库路径。5.4 编译 libpcap 时碰上 bison 版本过新grammar.c 报一堆 “undefined reference”现象bison 装的是 3.8 以上的新版本libpcap make 时 grammar.c 的编译输出里全是undefined reference to yylex、undefined reference to yyerror而且大多数出现在链接阶段。原因新版 bison 生成的 parser 代码默认采用 C99 的某些特性老 gcc 在默认的-stdgnu89模式下没有声明这些函数导致链接器找不到符号。这不是 libpcap 的 bug而是 bison 和 gcc 的版本组合问题。解决给 CFLAGS 加上-stdc99强制 gcc 按 C99 模式编译export CFLAGS-stdc99 ./configure --prefix$PREFIX --enable-shared --enable-static make -j$(nproc)如果加了-stdc99还报错那就把 bison 换成 3.7 左右的版本再试。这条坑在纯内网环境里特别容易遇到因为你拷进去的 bison 版本是固定的没法现场换源所以准备物料时最好确认一下目标机和 bison 的兼容性。5.5 脚本用了 set -e 却死在第一个 make 上日志却显示成功现象脚本开头写了set -e跑到 m4 的 make 时突然退出但打开m4.log看最后一行是编译正常完成的输出没有任何 error。原因make 本身会启动多个子进程其中某个子进程的退出码非零但主进程在并发模式下可能把它吞掉了或者是你用-j$(nproc)时某个 target 的依赖顺序没跑对报错后 make 自动重试成功但退出码已经被记录为失败。这种情况在set -e下会直接杀死脚本造成「日志显示成功、脚本判定失败」的假象。解决放弃裸set -e改用我在第 4 章脚本里的set -uo pipefail加die函数方案。每个编译步骤变成make -j$(nproc) $LOG_DIR/$pkg.log 21 || die $pkg make 失败这样即使 make 的退出码异常你也能从日志里看到到底是哪个阶段退出的而不是被set -e静默杀掉。另一个小技巧是不要对整段脚本用set -e只在关键命令后手动检查退出码脚本的容错性会好很多。6. 安装验证与后续扩展让同一套脚本在 CentOS 7、Kylin V10 上少踩几个坑6.1 验证三连pcap-config、tcpdump、libpcap.so 版本安装结束不等于万事大吉离线环境里没有在线包管理器帮你确认依赖所有验证都必须手动做。我习惯按下面三步走。第一步验证 libpcap 本身可用。用 pcap-config 确认版本和编译参数/usr/local/bin/pcap-config --version /usr/local/bin/pcap-config --libs正常输出会有一串-lpcap版本号出现在--version输出里。如果 pcap-config 都找不到说明 make install 阶段出了问题直接回第 4 章看日志。第二步验证动态库加载没有「黑匣子」问题ldd /usr/local/bin/tcpdump 2/dev/null | grep pcap这一步能直接看到 tcpdump 链接的是/usr/local/lib/libpcap.so.1还是老的/usr/lib64/libpcap.so.1。如果你拷进去的 tcpdump 是静态编译的ldd 不会有 pcap 输出那就要单独验证 libpcap.so 是否存在find /usr/local/lib /usr/local/lib64 -name libpcap.so* 2/dev/null第三步实际抓一把包验证 BPF 过滤器能跑通tcpdump -i any -c 3 tcp port 80 -w /tmp/test.pcap这条命令能同时验证 libpcap 的打开设备、编译过滤表达式、写 pcap 文件三条核心路径。过滤表达式一旦能编译通过说明 flex/bison 生成的解析代码在目标机上工作正常之前那一串依赖就没白装。6.2 给脚本加平台检测与保底策略适配 CentOS 7 和 Kylin V10我最后想分享的是平台兼容性。标题里这几个包在 CentOS 7、Kylin V10、Ubuntu 上都能编但细节差别很大。CentOS 7 自带的 gcc 4.8.5 编新版 libpcap 没问题但编 bison 3.8 会踩 5.4 那条坑Kylin V10 是 aarch64 架构的话还要注意/usr/local/lib64是否存在不存在时 ldconfig 配置别写在lib64上。我现在的做法是给脚本加一个平台探测段用uname -m和/etc/os-release识别系统再决定 yum 还是 apt、lib 还是 lib64build_ldconfig_conf() { local libdir if [ $(uname -m) x86_64 ]; then libdir/usr/local/lib64 else libdir/usr/local/lib fi echo $libdir /etc/ld.so.conf.d/pcap-offline.conf ldconfig }这段小函数能治 5.3 里提到的「新库装了但程序找不到」问题。第一次写离线安装脚本时我因为没区分 lib 和 lib64在 aarch64 机器上把动态库写进了不存在的 lib64 目录ldconfig 后一点效果都没有白白浪费了一下午。现在我做离线部署都会先把操作系统版本、架构、各组件版本写进 install.log方便后续排障时对齐环境。离线安装这件事本身不复杂复杂的是你不能像在线一样随手apt install补救所以每一步都要留证据、留日志、留版本号。希望这篇笔记能帮你把 libpcap 离线安装这条路一次走通少踩几个我踩过的坑。本文还有配套的精品资源点击获取