进程联网监控工具:WFN / Sniffnet / Picosnitch / LuLu
想知道"哪个进程偷偷联网"并实时弹通知,不同系统有不同的成熟开源方案。 Windows:Windows Firewall Notifier(WFN) 最接近需求的工具:进程发起网络连接时弹窗,可以选择允许或拒绝。 特点:基于 Windows 自带防火墙(WFP) 实时弹窗通知:显示进程名、目标 IP/域名、端口 允许/拒绝并记住规则 免费开源(GlassWire 的免费替代)安装后运行即可,不需要修改系统设置。 Windows / Linux / macOS:Sniffnet(流量可视化) Rust 编写,UI 现代,侧重流量监控而非拦截:显示哪个程序在联网、发送/接收了多少流量 支持桌面通知 可过滤特定协议或国家 跨平台(Windows/Linux/macOS)# Windows/macOS 下载安装包 # Linux cargo install sniffnet适合:想了解整体网络情况,而不是逐个审批连接请求。 Linux:Picosnitch eBPF 实现,低开销,功能最强: pip install picosnitch sudo picosnitch start功能:新进程联网时立即通知(systemd/D-Bus 通知) 按可执行文件统计流量 关联父进程(识别子进程发起的连接) 可选接入 VirusTotal 检查新进程 hash Web UI 查看历史记录配置文件(~/.config/picosnitch/config.json): { "Desktop notifications": true, "VT API key": "your_virustotal_api_key" }适合:需要安全审计,或在服务器上追踪异常网络行为。 macOS:LuLu macOS 下最受欢迎的免费联网防火墙:新连接弹窗(允许/拒绝/记住) 显示进程路径和目标地址 支持规则管理 Objective-See 出品(macOS 安全工具知名团队)下载安装包后启用,效果类似 Little Snitch(商业软件)的免费替代。 对比选择工具 系统 特点 是否可拦截WFN Windows 弹窗审批,集成防火墙 ✅Sniffnet 跨平台 流量可视化,UI 好看 ❌Picosnitch Linux eBPF,安全审计,VirusTotal ❌(仅监控)LuLu macOS 弹窗审批,免费 ✅根据场景选择 想控制哪些程序能联网:WFN(Windows)、LuLu(macOS) 想看流量统计和来源:Sniffnet(跨平台) 服务器安全审计/发现异常进程:Picosnitch(Linux) 排查可疑进程(如挖矿木马):先用 Picosnitch/WFN 发现网络连接,再配合 ss -antp | grep <PID> 查目标 IP
Windows 编译 DLL:MSVC cl.exe 与 MinGW g++ 对比
最小示例 dllmain.cpp: #include <windows.h> #include <stdio.h>extern "C" __declspec(dllexport) void HelloFromDll() { MessageBoxA(NULL, "Hello from DLL", "DLL", MB_OK); }BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { return TRUE; }MSVC cl.exe 编译 cl /LD /EHsc /Y- dllmain.cpp user32.lib参数说明:参数 含义/LD 编译为 DLL(输出 .dll + .lib)/LDd Debug 版 DLL/EHsc 启用 C++ 标准异常处理/Y- 禁用预编译头(避免找不到 pch.h)user32.lib 链接 user32(MessageBox 所在库)必须在正确的命令提示符里运行 普通 cmd 里没有 cl 命令,必须用: 开始菜单 → Visual Studio 20xx → x64 Native Tools Command Prompt for VS 20xx 或在普通 cmd 里手动初始化: call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" cl /LD /EHsc /Y- dllmain.cpp user32.libvcvars64.bat 路径随 VS 版本和安装目录变化,注意替换。 输出文件 成功后生成:dllmain.dll — 动态链接库 dllmain.lib — 导入库(供其他项目链接用) dllmain.exp — 导出表MinGW g++ 编译(不需要 VS) 安装 MinGW 后: g++ -shared -o test.dll dllmain.cpp -luser32或指定目标架构: x86_64-w64-mingw32-g++ -shared -o test.dll dllmain.cpp -luser32MinGW 编译的 DLL 默认导出所有 extern "C" 函数,不需要 .def 文件。 预编译头问题(/Y-) VS 新建项目默认启用预编译头,会生成 pch.h 和 pch.cpp。手写 .cpp 文件如果没有包含 pch.h,编译时报: fatal error C1010: unexpected end of file while looking for precompiled header解决方法:加 /Y- 禁用预编译头(适合独立小文件) 在每个 .cpp 第一行加 #include "pch.h" 在文件属性里设置「不使用预编译头」导出函数声明 C++ 有 name mangling,跨语言调用需要 extern "C" 防止符号被修饰: // 头文件 #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endifextern "C" MYDLL_API int Add(int a, int b);用 .def 文件显式指定导出名(不受 extern "C" 影响): LIBRARY mydll EXPORTS Add @1 Hello @2编译时加 /DEF:mydll.def。 验证导出 dumpbin /exports dllmain.dll或用 Dependency Walker、x64dbg 查看导出表。
开源进程联网通知工具:Windows / Linux / macOS 对比
需求场景 想知道哪个进程在悄悄联网、连的是什么地址,并在出现新连接时弹出通知或提示。 Windows:Windows Firewall Notifier(WFN) GitHub: LeBlue/wfn 基于 Windows 内置防火墙的审计日志,当有进程触发出站连接时弹出通知气泡,可以选择「允许」或「拒绝」,行为类似 macOS 的 LuLu。 特点:不需要驱动,利用 Windows 防火墙事件日志(Event ID 5156/5157) 支持创建防火墙规则白名单 .NET 实现,需要 .NET Runtime启动前需要启用 Windows 防火墙的连接日志: # 以管理员身份运行 auditpol /set /subcategory:"Filtering Platform Connection" /success:enable /failure:enableWindows:Sniffnet(Rust 跨平台) GitHub: GyulyVGC/sniffnet 用 Rust 编写的网络流量监控工具,有图形界面,实时显示每个连接的进程、IP、国家、流量统计。 特点:跨平台(Windows / Linux / macOS) 可过滤特定进程或协议 流量图表可视化 不能主动拦截,只做监控和统计适合想直观看到哪些进程在产生流量、流量走向哪里的场景。 Linux:Picosnitch(eBPF) GitHub: elesiuta/picosnitch 基于 eBPF 的进程网络监控,内核级捕获,开销极低。 特点:记录每个进程的 DNS 查询和连接 SQLite 存储历史 支持通知(desktop notification) 需要 Linux 5.8+ 内核和 root 权限安装: pip install picosnitch sudo picosnitch startmacOS:LuLu GitHub: objective-see/LuLu Objective-See 出品的免费防火墙,功能类似商业的 Little Snitch。 特点:新进程首次出站连接时弹出授权窗口 可以创建规则(允许/拒绝) 显示进程路径、签名、目标地址对比工具 平台 技术原理 能拦截 特点WFN Windows 防火墙审计日志 是 弹窗授权Sniffnet 跨平台 pcap 否 流量可视化Picosnitch Linux eBPF 否 低开销,历史记录LuLu macOS 内核扩展 是 弹窗授权,免费想要拦截 + 弹窗授权:Windows 用 WFN,macOS 用 LuLu。只想监控流量走向:Sniffnet 最直观。Linux 生产环境审计:Picosnitch + SQLite 日志。
systemd Service 设置工作目录:WorkingDirectory 与 ExecStart 相对路径
systemd service 文件通过 WorkingDirectory 指令设置进程启动后的工作目录,等同于 cd 后再执行命令。 基本配置 [Unit] Description=My App Service[Service] Type=simple User=www-data WorkingDirectory=/opt/myapp ExecStart=/usr/bin/python3 main.py Restart=always RestartSec=5[Install] WantedBy=multi-user.target设置 WorkingDirectory=/opt/myapp 后:ExecStart 中的相对路径基于 /opt/myapp 程序内 os.getcwd()(Python)或 process.cwd()(Node.js)返回 /opt/myapp 读写相对路径的文件(如 config.json、logs/)都指向该目录修改配置后重新加载 sudo systemctl daemon-reload sudo systemctl restart myapp.service# 查看服务状态 systemctl status myapp.service每次修改 .service 文件都需要 daemon-reload,否则 systemd 不会读取新配置。 常见问题 User 与目录权限 如果指定了 User=www-data,该用户必须对 WorkingDirectory 有读取权限(通常还需要写权限): sudo chown www-data:www-data /opt/myapp sudo chmod 750 /opt/myapp带有空格的路径 WorkingDirectory=/opt/my app/ # 错误,空格无需引号但会导致解析问题 WorkingDirectory="/opt/my app" # 正确,用引号包裹ExecStart 中用绝对路径 ExecStart 建议始终用绝对路径,避免 $PATH 不同导致找不到命令: ExecStart=/usr/bin/node /opt/myapp/server.js # 不要写:ExecStart=node server.js查看服务文件位置 # 列出所有用户服务文件 ls /etc/systemd/system/# 查看某个服务的完整配置(包括覆盖) systemctl cat myapp.service服务文件通常放在 /etc/systemd/system/ 下,命名为 <name>.service。
systemd 服务里设置工作目录:WorkingDirectory
写 Python / Node 服务的 systemd 单元时,程序里各种相对路径都得基于"工作目录"来解读。systemd 提供了 WorkingDirectory 字段,比在 ExecStart 里 cd 一下再启动规范得多。 最简单的例子 [Unit] Description=My App After=network-online.target[Service] Type=simple User=appuser WorkingDirectory=/opt/myapp ExecStart=/usr/bin/python3 main.py Restart=always RestartSec=3[Install] WantedBy=multi-user.targetWorkingDirectory=/opt/myapp 的效果:进程启动时 cwd 就是这个目录 ExecStart 里的相对路径按它算(比如 python3 main.py 就是 /opt/myapp/main.py) Python 里 os.getcwd() 返回这个目录 写日志到 ./logs/app.log 就是 /opt/myapp/logs/app.log为什么不用 cd 见过这种写法: ExecStart=/bin/bash -c 'cd /opt/myapp && python3 main.py'能跑,但坏处一堆:多一层 shell,进程树多了个 bash 语义没那么直观 systemd 的 Restart / 信号处理会作用在 bash 上,不是真进程 环境变量、User、日志跟你想的不一样能用字段就用字段,cd 是最后的兜底。 常配套的字段 User / Group 以指定用户启动,不用 root 跑业务: User=appuser Group=appuser注意 WorkingDirectory 里的目录必须让这个用户能读、能进: sudo chown -R appuser:appuser /opt/myappEnvironmentFile 把环境变量放外面,方便修改: EnvironmentFile=/etc/myapp/envenv 文件内容: DATABASE_URL=postgres://user:pass@localhost/mydb APP_PORT=8000代码里 os.getenv("DATABASE_URL") 就能拿到。 Restart 崩溃后的行为: Restart=always # 无条件重启 RestartSec=3 # 3 秒后重启 StartLimitInterval=60 # 60 秒内 StartLimitBurst=5 # 最多重启 5 次,再多就放弃生产上都需要——不然崩了以后就得手动来。 日志 默认 stdout / stderr 会走 journald: journalctl -u myapp -f journalctl -u myapp --since "10 minutes ago"想直接写文件: StandardOutput=append:/var/log/myapp/out.log StandardError=append:/var/log/myapp/err.logappend: 需要 systemd 240+,老版本用 file:。 一个"生产可用"的模板 [Unit] Description=My FastAPI App After=network-online.target Wants=network-online.target[Service] Type=simple User=appuser Group=appuser WorkingDirectory=/opt/myapp EnvironmentFile=/etc/myapp/env ExecStart=/opt/myapp/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 Restart=always RestartSec=3 StartLimitBurst=5 StandardOutput=journal StandardError=journal[Install] WantedBy=multi-user.target启用: sudo systemctl daemon-reload sudo systemctl enable --now myapp sudo systemctl status myapp一句话总结 WorkingDirectory=/path 就是 cwd,不要在 ExecStart 里套 bash -c 'cd ... && ...'。搭配 User、EnvironmentFile、Restart 一份 systemd 单元就是完整的服务定义。
