十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

离线环境libpcap源码编译安装攻略:依赖链与排错指南

离线环境libpcap源码编译安装攻略:依赖链与排错指南 简介libpcap数据包捕获函数库是Unix/Linux平台上广泛使用的网络数据包捕获开发库支持原始数据包捕获、自定义数据包发送、流量采集统计与规则过滤也是tcpdump、Wireshark等常见网络工具的重要底层依赖。但在离线、内网或无外网编译环境下手动编译libpcap常被gcc、m4、bison、flex等依赖项卡住版本不匹配或安装顺序错误都会导致反复报错。压缩包内共2个文件包括1个tar源码包和1个sh安装脚本总大小43.29MB其中的sh脚本可自动完成编译与安装并已包含libpcap 1.10.1及全套依赖源码。目前已有1036人学习/下载说明该离线安装方案具备较高的参考价值。开启资源后读者可在不联网的服务器或实验环境中直接运行脚本免去逐个下载、编译依赖的繁琐流程保留的完整依赖源码也便于核对版本、排查安装异常并在其他离线机器上重复使用适合Linux运维、网络安全测试及希望快速搭建抓包开发环境的开发者。 干内网运维或者安全分析的朋友多半遇到过这种场景机器上要排查流量问题需要tcpdump跑过去一敲命令发现gcc没有、make没有yum连不上外网手里只有一个U盘。系统装不上libpcap抓包工作就卡在原地。libpcap本身是个很成熟的库从源码编译并不复杂麻烦的是它背后站着一串编译工具和辅助库——gcc、m4、bison、flex一个都不能缺而且安装顺序有讲究。这篇文章把我最近一次在完全离线的CentOS 7环境里搞定libpcap的完整过程整理出来包括自动安装脚本的设计思路、版本搭配的选择逻辑以及实际执行中最容易翻车的几个报错和完整排查方法。如果你也遇到内网要装libpcap这类需求可以直接把脚本拿走用报错排查部分也值得先看一眼能帮你少走不少弯路。1. libpcap不是单个包而是一条依赖链1.1 抓包需求背后的完整编译链路libpcap是一个捕包接口库tcpdump、nmap、wireshark这些工具底层都在依赖它。它的工作方式是从网卡驱动那里拿到原始数据帧再按pcap格式交给上层应用。在内网里排查ARP攻击、看某台机器到底发了什么包都绕不开它。问题在于从源码安装libpcap并不是解压、make、make install三个命令这么简单。整个编译过程要经历configure、make、make install三个阶段而每个阶段都依赖外部工具configure阶段需要一套完整的POSIX工具链包括sed、awk、sh这些通常最小化安装的CentOS也会带。make阶段需要make本身这个很多系统会忽略。代码生成阶段libpcap源码里的过滤器表达式解析器是用bison生成的grammar.y词法扫描器是用flex生成的scanner.l。如果发布包里没有预生成代码或者configure检测不到flex和bison编译就直接中断。C代码编译阶段需要gcc这套真正的C编译器。而这些工具自身也还有下一层依赖。bison是C语言写的编译它的时候configure脚本会调用m4来完成一些宏展开flex同样对m4有版本要求。m4是老古董级的宏处理器但Bison和Flex的构建体系到现在依然重度依赖它。1.2 每个依赖在整条链里具体干什么很多教程只说把gcc、m4、bison、flex装上就行但从没讲清楚为什么。这里我展开说一下理解之后你排查问题会快得多gcc把C源码编译成目标文件和可执行程序。libpcap、flex、bison都是C/C项目没有编译器寸步难行。make根据Makefile规则按依赖关系自动编译和安装。configure会生成Makefile但执行构建还得有make。m4宏处理器。autoconf生成的configure脚本会自动搜索m4bison构建时会调用m4处理一些数据文件。很多老系统带的m4版本过低直接导致bison或flex的configure报错。flex词法分析器生成器。libpcap中负责把输入字节流切成token对应的源文件是scanner.l。bison语法分析器生成器。libpcap中负责把token组合成语法树用于过滤表达式解析对应的源文件是grammar.y。它们之间是一个串行依赖gcc和make在最底层m4在中间层flex和bison在上层最后才是libpcap。顺序反了后一个包的configure就会检测不到前置工具然后给你一句莫名其妙的错误。1.3 为什么不能靠yum一把梭在有网环境下一条yum install -y libpcap libpcap-devel就能解决包管理器会自动把glibc、flex、bison这些依赖全部拉起来。可一旦到了物理隔离的内网yum源不可用你手里唯一的途径就是手动搬运安装包。如果只搬一个libpcap的rpm回来安装时会报一堆依赖缺失如果你对依赖链没有全局认识就会陷入装A发现缺B装B发现缺C装C又发现A版本不够的死循环。提前把整条链理清楚比临时去试要高效得多。2. 依赖包版本搭配不同环境的选型逻辑2.1 我建议的版本组合离线环境里选版本我的原则是能稳定编译通过优先其次再去追新。如果目标系统是CentOS 7下面这套版本组合我实测比较稳软件包建议版本作用备注gcc / gcc-c系统自带4.8.x即可C/C编译器无需升级除非要编新版bisonmake系统自带3.82构建工具一般默认就有m41.4.19宏处理器别用太旧的1.4.16flex2.6.4词法分析器生成器2.5.x也能用2.6.x更稳bison3.0.4语法分析器生成器老gcc环境下别上3.7libpcap1.10.4抓包库本体1.10系比较稳定2.2 版本选择的底层依据为什么bison这里我特意压到3.0.4很多人会不理解。因为新版bison从3.5往后构建bison自身源码需要较完整的C11编译器支持CentOS 7自带的g是4.8.5只支持部分C11特性。虽然在某些场景下能勉强编过但一旦碰到模板展开或正则表达式库相关代码就会抛出一堆看不懂的报错。而libpcap对bison版本的要求其实没那么苛刻只要语法分析器输出正常3.0.4完全够用。反过来如果你的目标机器g版本在8以上比如比较新的Linux发行版那就可以放心用bison 3.8.2。所以我建议把bison版本做成一个可配置的变量而不是在脚本里写死。m4版本也不能胡来。flex 2.6.4的configure脚本会检查m4版本低于1.4.6直接拒绝。CentOS 7自带的m4是1.4.16其实够用但如果你装了新的bison 3.8它对m4的要求会更高。统一用m4 1.4.19最省心。2.3 一个版本搭配表给不同环境做个快速选型参考目标系统gcc/gm4flexbisonlibpcapCentOS 7 / RHEL 74.8.5自带1.4.192.6.43.0.41.10.4CentOS 8 / RHEL 88.x自带1.4.192.6.43.7.61.10.4Ubuntu 20.049.x自带1.4.182.6.43.8.21.10.4老旧机器gcc偏低需自备或rpm源1.4.192.5.392.7.11.9.1这个表不是绝对的但按这个组合走踩坑概率会小很多。3. 装之前先做环境体检判断哪些依赖能省3.1 体检命令离线环境下每多编一个包就多一分风险所以第一步不是闷头装而是先看机器上已经有什么。我自己习惯把这几个命令一次性跑完cat /etc/redhat-release getconf LONG_BIT which gcc g make m4 flex bison yacc lex 2/dev/null gcc --version 2/dev/null | head -1 make --version 2/dev/null | head -1 m4 --version 2/dev/null | head -1 rpm -q kernel-devel glibc-devel libgcc 2/dev/null echo $PATH输出结果会告诉你两件事哪些工具已经有了哪些工具虽然有但可能不完整。比如gcc命令存在不代表g也存在因为RHEL系列把gcc和gcc-c分成了两个包最小化安装经常只带gcc不带g。3.2 体检结果怎么判断判断逻辑其实很简单gcc存在且能正常编译hello world那么gcc这个依赖就可以跳过不必非得离线编译一遍gcc那是个巨大的工程。make存在基本就不用管了make 3.82编这些包没有兼容性问题。m4存在且版本不低于1.4.16可以先用着如果configure报错再换。flex和bison大概率是没有的因为它们是开发工具生产服务器一般不装。kernel-devel一定重点看libpcap在Linux上需要内核头文件来定义packet socket相关结构缺了它后续编译出的libpcap功能不完整。3.3 最常见的半吊子环境我遇到最多的情况是用户说机器上有gcc结果一查只有gcc的rpm记录gcc命令压根不存在或者gcc命令在但缺少libc库的开发头文件。有一个隐蔽的坑gcc --version能输出版本号但实际编译一个最简单的.c文件时报fatal error: stdio.h: No such file or directory这说明glibc-devel没装头文件路径是空的。离线环境下这种问题最容易让人抓狂因为你根本没想到编译器本体在头文件却不在。所以体检阶段我强烈建议顺手在/tmp下写个hello.c执行一遍gcc hello.c -o hello ./hello确认它能真正产出可执行文件。这个检查花不了一分钟却能过滤掉一大半假环境问题。4. 离线安装包怎么来ISO本地源、yumdownloader与源码包4.1 方案一用CentOS ISO做本地yum源如果手里有CentOS 7的ISO镜像这是最省事的路子。挂载ISO配置一个本地yum源gcc、gcc-c、make、kernel-devel一次性装齐半小时内搞定基础编译链。具体做法mkdir -p /mnt/centos mount -o loop /path/to/CentOS-7-x86_64-DVD-1810.iso /mnt/centos cat /etc/yum.repos.d/local.repo EOF [local] nameCentOS-$releasever - Local baseurlfile:///mnt/centos enabled1 gpgcheck0 EOF yum clean all yum makecache yum install -y gcc gcc-c make kernel-devel注意ISO里的包一般是发行版发布时的版本版本偏老些没关系编译libpcap完全够用。装完后建议把kernel-devel版本和系统内核版本对一下执行uname -r确认因为内核开发包必须匹配当前内核才能正确编译内核模块不过libpcap走的是packet socket不需要编译内核模块这里主要是为了拿到头文件。4.2 方案二联网机器抓rpm包搬运如果没有ISO但内网有一台可以联网的同版本机器可以用yumdownloader把依赖的rpm全部抓下来再通过U盘或内网传输搬到目标机。步骤yum install -y yum-utils mkdir -p /tmp/rpms yumdownloader --resolve --destdir/tmp/rpms \ gcc gcc-c make kernel-devel glibc-devel tar czf rpms.tar.gz /tmp/rpms把rpms.tar.gz拷到目标机器后mkdir -p /tmp/rpms tar xzf rpms.tar.gz -C /tmp/rpms yum install -y /tmp/rpms/rpms/*.rpm这个方式的坑在于yumdownloader --resolve只解决rpm依赖不会把非rpm方式安装的源码包依赖也一起解决。而且如果两台机器的系统小版本差距过大抓来的包可能因为glibc版本不兼容而装不上。所以尽量找同一版本、同一架构的机器。4.3 方案三源码包编译源码包方式是我这篇脚本的主线。它的优点是不依赖rpm仓库理论上任何Linux发行版都能用缺点是每个包都要自己configure、make、make install一遍。离线机器上源码包需要提前备好目录结构我习惯这样规划/opt/src/ ├── m4-1.4.19.tar.gz ├── flex-2.6.4.tar.gz ├── bison-3.0.4.tar.gz └── libpcap-1.10.4.tar.gz下载的时候我建议在联网机器上同时执行sha256sum生成校验值目标机解压前先核对防止U盘或网络传输过程中文件损坏。以前我偷懒跳过这一步结果flex的压缩包在拷贝时损坏解压能成但configure阶段报一堆乱码排查了好久才发现是包坏了。另外提一句源码包尽量从官方FTP或GitHub release下载不要随便找个镜像站被篡改的源码一旦编译进生产环境问题会很严重。官方校验值要一并核对。5. 自动安装脚本顺序、环境变量和失败即停5.1 完整脚本核心思路就三句话按依赖顺序编译、统一环境变量、失败立即终止。下面是简化后可用的完整脚本我已经在CentOS 7上跑过#!/bin/bash # libpcap offline auto installer # Usage: bash install_libpcap.sh [source_dir] [install_dir] set -euo pipefail SRC_DIR${1:-/opt/src} INSTALL_DIR${2:-/usr/local} LOG_FILE/tmp/libpcap_install.log # 统一依赖的安装路径 export PATH${INSTALL_DIR}/bin:${PATH} export CPPFLAGS-I${INSTALL_DIR}/include export LDFLAGS-L${INSTALL_DIR}/lib -L${INSTALL_DIR}/lib64 export LD_LIBRARY_PATH${INSTALL_DIR}/lib:${INSTALL_DIR}/lib64:${LD_LIBRARY_PATH:-} export PKG_CONFIG_PATH${INSTALL_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH:-} log() { echo $(date %Y-%m-%d %H:%M:%S) $* | tee -a ${LOG_FILE} } build_pkg() { local pkg_dir$1 shift if [ ! -d ${SRC_DIR}/${pkg_dir} ]; then log [ERROR] source dir not found: ${SRC_DIR}/${pkg_dir} return 1 fi cd ${SRC_DIR}/${pkg_dir} log build ${pkg_dir} if [ ! -f Makefile ]; then ./configure --prefix${INSTALL_DIR} $ ${LOG_FILE} 21 || { log [ERROR] configure failed for ${pkg_dir} return 1 } fi make -j$(nproc) ${LOG_FILE} 21 || { log [ERROR] make failed for ${pkg_dir} return 1 } make install ${LOG_FILE} 21 || { log [ERROR] make install failed for ${pkg_dir} return 1 } log [OK] ${pkg_dir} installed } # ---------- build order ---------- build_pkg m4-1.4.19 build_pkg flex-2.6.4 build_pkg bison-3.0.4 build_pkg libpcap-1.10.4 # 让动态链接器找到新的libpcap.so echo ${INSTALL_DIR}/lib /etc/ld.so.conf.d/offline-libpcap.conf echo ${INSTALL_DIR}/lib64 /etc/ld.so.conf.d/offline-libpcap.conf ldconfig log all done 5.2 脚本设计的六个关键点为什么脚本要这么写而不是简单地一条条命令堆下去有六个细节值得说第一set -euo pipefail是底线。-e让脚本在第一个报错时退出-u防止未定义变量在脚本里炸出意想不到的路径-o pipefail让管道前一个命令失败时整条管道返回失败。离线编译最怕脚本跑了一半把错误忽略掉最后装出来一个残缺的libpcap后续排查更痛苦。第二build_pkg函数把configure、make、make install封装成了三次独立检查。为什么不在configure成功后就默认make一定成功因为configure阶段检查的是环境make阶段暴露的是源码编译问题二者失败原因完全不同。分开记录日志和错误能让你快速定位到底卡在哪一步。第三--prefix统一指定为/usr/local这比默认值更重要。如果不显式指定flex默认装在/usr/local还好但有些包默认已经配置了别的路径导致头文件和库文件散落多处后面libpcap configure时找不到flex的库就得去猜路径。第四环境变量必须在编译开始前export。CPPFLAGS和LDFLAGS的作用是告诉后面的configure和make所有依赖的头文件和库文件都在/usr/local/include和/usr/local/lib下。这几个变量不设即使把依赖都装好了后面的包还是找不到它们。第五安装顺序是硬性的m4 - flex - bison - libpcap。为什么flex在bison前面因为bison的configure脚本会用m4flex的configure脚本也会用m4但二者之间没有强依赖。而libpcap在configure阶段需要同时看到flex和bison所以它必须在最后。第六ldconfig和ld.so.conf.d文件不能省。libpcap编译完如果不刷新动态链接器缓存运行tcpdump时会报libpcap.so.1: cannot open shared object file。这个问题在后续验证阶段会出现所以脚本里提前处理掉。5.3 脚本怎么扩展实际使用时你可能有自己的版本偏好把版本号改成3.8的bison只需改相应的目录名即可。但注意如果换用bison 3.7那执行脚本前必须确认g版本够新。另外如果你的目标机器已经有部分依赖比如系统自带m4且版本满足完全可以跳过对应的build_pkg行不必重复编译。如果文件是tar.xz或tar.bz2脚本里没写解压逻辑因为我觉得解压动作应该在脚本外手动完成更可控。执行前把所有tar包预先解压到/opt/src下再跑脚本避免脚本误删或覆盖已有源码目录。6. 实际执行时最常翻车的4个报错与排查思路6.1 configure: error: GNU M4 1.4.6 or later is required这是编译flex或bison时最常见的报错。症状很直白./configure执行到一半抛出一句要求M4版本大于等于1.4.6然后退出。排查链路是这样的先看日志尾部确认是哪个包报的错。然后用m4 --version查看本机m4版本。CentOS 7自带m4是1.4.16按理说满足要求但如果你的PATH里没有把/usr/local/bin放进去configure会优先找到系统老版本的m4如果本机m4缺失那configure直接说找不到。解决办法就是先把m4装上。装m4本身没什么坑三步走完。但如果你用的是我上面的脚本脚本已经设置了PATH包含${INSTALL_DIR}/bin所以configure会在m4安装后被正确找到。这里特别提醒一句千万不要跳过m4直接编flex很多人在这一步节省时间最后反而花更多时间排查。6.2 flex is required / yacc: command not foundlibpcap的configure脚本在检测flex和bison时会明确检查版本和路径。如果你跳过了flex或者flex装到了非标准路径configure会报configure: error: flex is required如果flex装了但bison没装到make阶段会出现yacc: command not found。这里有个容易混淆的细节libpcap的Makefile里语法分析器通常通过YACC变量调用而YACC通常指向bison -y。有些系统上你只装了bison但/usr/bin/yacc这个符号链接不存在make就会报找不到yacc。排查方法很简单which yacc flex bison ls -l /usr/bin/yacc如果yacc不存在创建符号链接ln -s /usr/local/bin/bison /usr/bin/yacc不过这个方案比较粗暴。更干净的做法是确保bison安装路径在PATH里并重新运行libpcap的configure脚本让configure重新检测YACC变量并写入Makefile。6.3 cannot find -lfl / undefined reference to libfl这个错一般发生在你重新编译其他依赖libpcap的程序时或者在编译过程中某个测试程序链接flex库时。-lfl指的就是libfl.aflex安装后生成的词法分析器库。报这个错最直接的原因是flex编译安装成功了但libfl库的路径没被链接器找到。CentOS 7的链接器默认搜索路径里不包含/usr/local/lib你明明看到/usr/local/lib/libfl.a存在链接器就是找不到。排查和解决思路ls -l /usr/local/lib/libfl* echo ${LDFLAGS} echo ${LD_LIBRARY_PATH} ldconfig -p | grep fl如果LDFLAGS里没加-L/usr/local/lib把它补上重新编译如果动态库运行时报找不到libfl.so确认/etc/ld.so.conf.d/offline-libpcap.conf里的路径正确并执行了ldconfig。这个坑属于装完必须配路径的经典案例很多初学者栽在这里因为安装本身成功了问题出在后续使用阶段。6.4 g: command not found如果你用的bison版本是3.7以上编译bison时configure会检测C编译器因为新版bison的源码是C写的。这个时候一个古老但常见的坑就出现了系统装了gcc但没装gcc-c。排查方式which g g --version如果输出是空的说明gcc-c缺失。解决办法有两个一是用之前讲过的ISO本地源或yumdownloader方式补装gcc-c二是把bison版本换成3.0.4这样它还是纯C的构建体系不要求g。我个人的建议是如果只是为了编libpcapbison 3.0.4足矣没必要为了追新去折腾g。除非你的项目需要用到新版bison生成特定语法否则少引入一个变量就少一份风险。7. 装完验证三件套库、编译、真实抓包7.1 库文件确认安装完成后先确认libpcap库确实存在于预期位置ls -l /usr/local/lib/libpcap* ls -l /usr/local/include/pcap* ldconfig -p | grep pcap如果ldconfig -p里能看到pcap相关的输出说明动态链接器已经识别了新的库。如果看不到检查/etc/ld.so.conf.d/offline-libpcap.conf文件是否创建并执行ldconfig。7.2 用一个小程序验证API调用库文件在不在不等于API能正常调用。写一个几十行的C程序调用pcap_findalldevs枚举网卡这是确认libpcap真正工作的最小验证#include stdio.h #include pcap/pcap.h int main(void) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *alldevs NULL; if (pcap_findalldevs(alldevs, errbuf) -1) { fprintf(stderr, pcap_findalldevs: %s\n, errbuf); return 1; } for (pcap_if_t *d alldevs; d ! NULL; d d-next) { printf(%s\n, d-name); } pcap_freealldevs(alldevs); return 0; }编译时用下面的命令注意-L和-l参数顺序-lpcap必须放在源码文件后面gcc -o test_pcap test_pcap.c -I/usr/local/include -L/usr/local/lib -lpcap ./test_pcap正常情况下会输出eth0、lo之类的网卡名称。如果程序报error while loading shared libraries: libpcap.so.1说明动态链接器还没找到库路径回到7.1检查ldconfig配置。我还用ldd test_pcap看过它的动态库依赖能看到libpcap.so.1 /usr/local/lib/libpcap.so.1这样的输出这能确认程序实际链接的库来自哪里也方便排查是不是链接到了系统自带的旧版libpcap。7.3 tcpdump验证真实抓包API能跑了还不够最好用tcpdump直接抓一下包验证内核态的packet socket确实可用tcpdump -i eth0 -c 5如果tcpdump还没装可以同样离线编译一个它的依赖只有libpcap无需其他额外工具。也可以先用tcpdump -D列出网卡确认tcpdump能识别到接口。能抓到包说明从libpcap到内核packet socket整条链路都是通的。7.4 环境变量持久化最后一个小细节脚本里export的环境变量只对当前shell有效。为了下次登录不用重新配置在/etc/profile.d/libpcap_offline.sh写入export PATH/usr/local/bin:$PATH export LD_LIBRARY_PATH/usr/local/lib:/usr/local/lib64:$LD_LIBRARY_PATHsource一下再验证。这样以后别的用户登录也会自动带上这些路径避免临时环境变量忘记设置导致各种找不到库的诡异问题。我在实际用途中体会最深的一点是离线安装这类工具链真正难的不是某个包编译不过而是对整体依赖链缺乏全局认识导致反复试错每层都试一遍才摸清顺序。这份脚本和对应的排查思路我现在遇到内网机器就直接复用从拆包到tcpdump能抓包基本五分钟内结束。如果你也常处理离线环境建议把这套流程固化成自己的工具包遇到一台新机器就按体检、补基础链、编译依赖、编译本体、验证这个节奏走效率会高很多。本文还有配套的精品资源点击获取
返回列表