feat: add cross-platform packaging and release automation

- Add GitHub Actions workflow for automated releases
- Create .deb, .rpm, AppImage, .dmg, and .msi packages
- Generate shell completions and manpages in build.rs
- Add platform-specific icons from rustnet3.svg
- Include eBPF dependencies for Linux packages
- Support Windows 32-bit and 64-bit builds
- Extract shared CLI module to prevent duplication
This commit is contained in:
Marco Cadetg
2025-09-29 11:56:55 +02:00
parent b642205e38
commit eca0e6000d
20 changed files with 1244 additions and 60 deletions

357
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,357 @@
name: Release
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
workflow_dispatch:
env:
RUST_BACKTRACE: 1
RUSTNET_ASSET_DIR: assets
jobs:
build-release:
name: build-release
runs-on: ${{ matrix.os }}
strategy:
matrix:
build:
- linux-aarch64-gnu
- linux-aarch64-musl
- linux-armv7-gnueabihf
- linux-armv7-musleabihf
- linux-x64-gnu
- linux-x64-musl
- macos-aarch64
- macos-x64
- windows-x64-msvc
- windows-x86-msvc
include:
- os: ubuntu-latest # default
- cargo: cargo # default; overwrite with `cross` if necessary
- build: linux-aarch64-gnu
target: aarch64-unknown-linux-gnu
cargo: cross
- build: linux-aarch64-musl
target: aarch64-unknown-linux-musl
cargo: cross
- build: linux-armv7-gnueabihf
target: armv7-unknown-linux-gnueabihf
cargo: cross
- build: linux-armv7-musleabihf
target: armv7-unknown-linux-musleabihf
cargo: cross
- build: linux-x64-gnu
target: x86_64-unknown-linux-gnu
- build: linux-x64-musl
target: x86_64-unknown-linux-musl
- build: macos-aarch64
os: macos-14
target: aarch64-apple-darwin
- build: macos-x64
os: macos-14
target: x86_64-apple-darwin
- build: windows-x64-msvc
os: windows-latest
target: x86_64-pc-windows-msvc
- build: windows-x86-msvc
os: windows-latest
target: i686-pc-windows-msvc
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Linux dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update -y
sudo apt-get install -y libpcap-dev libelf-dev clang llvm
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Install cross
if: matrix.cargo == 'cross'
uses: taiki-e/cache-cargo-install-action@v2
with:
tool: cross
git: https://github.com/cross-rs/cross.git
rev: 085092c
- name: Build release binary
shell: bash
env:
RUSTFLAGS: "-C strip=symbols"
run: |
mkdir -p "$RUSTNET_ASSET_DIR"
# build.rs will handle Npcap SDK download on Windows
${{ matrix.cargo }} build --verbose --release --target ${{ matrix.target }}
- name: Create release archive
shell: bash
env:
RUSTNET_BIN: ${{ contains(matrix.os, 'windows') && 'rustnet.exe' || 'rustnet' }}
run: |
staging="rustnet-${{ github.ref_name }}-${{ matrix.target }}"
mkdir -p "$staging"
# Copy binary
cp "target/${{ matrix.target }}/release/$RUSTNET_BIN" "$staging/"
# Copy assets if they exist
if [ -d "$RUSTNET_ASSET_DIR" ]; then
cp -r "$RUSTNET_ASSET_DIR" "$staging/"
fi
# Copy documentation
cp README.md "$staging/"
cp LICENSE "$staging/" 2>/dev/null || true
# Create archive
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
7z a "$staging.zip" "$staging"
echo "ASSET=$staging.zip" >> $GITHUB_ENV
else
tar czf "$staging.tar.gz" "$staging"
echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV
fi
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.target }}
path: ${{ env.ASSET }}
if-no-files-found: error
create-release:
name: create-release
runs-on: ubuntu-latest
needs: build-release
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Create the release
gh release create ${{ github.ref_name }} \
--title "Release ${{ github.ref_name }}" \
--draft \
--generate-notes
# Upload all build artifacts
for artifact in artifacts/build-*/rustnet-*; do
gh release upload ${{ github.ref_name }} "$artifact"
done
package-installers:
name: package-installers
runs-on: ubuntu-latest
needs: create-release
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y libpcap-dev libelf-dev clang llvm
- name: Install Rust and tools
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf
- name: Install packaging tools
run: |
cargo install cargo-deb cargo-generate-rpm
- name: Package Debian packages
run: |
mkdir -p installers
for arch in amd64 arm64 armhf; do
case $arch in
amd64) target="x86_64-unknown-linux-gnu" ;;
arm64) target="aarch64-unknown-linux-gnu" ;;
armhf) target="armv7-unknown-linux-gnueabihf" ;;
esac
# Extract binary from artifact
tar -xzf "artifacts/build-$target/rustnet-${{ github.ref_name }}-$target.tar.gz"
mkdir -p "target/$target/release"
cp "rustnet-${{ github.ref_name }}-$target/rustnet" "target/$target/release/"
# Create deb package
cargo deb --no-build --no-strip --target $target
mv "target/$target/debian"/*.deb "installers/Rustnet_LinuxDEB_$arch.deb"
# Clean up for next iteration
rm -rf "rustnet-${{ github.ref_name }}-$target" "target/$target"
done
- name: Package RPM packages
run: |
for arch in x86_64 aarch64; do
target="$arch-unknown-linux-gnu"
# Extract binary from artifact
tar -xzf "artifacts/build-$target/rustnet-${{ github.ref_name }}-$target.tar.gz"
mkdir -p "target/$target/release"
cp "rustnet-${{ github.ref_name }}-$target/rustnet" "target/$target/release/"
# Fix library linking if needed
patchelf --replace-needed libpcap.so.0.8 libpcap.so.1 "target/$target/release/rustnet" 2>/dev/null || true
# Create rpm package
cargo generate-rpm --target $target
mv "target/$target/generate-rpm"/*.rpm "installers/Rustnet_LinuxRPM_$arch.rpm"
# Clean up for next iteration
rm -rf "rustnet-${{ github.ref_name }}-$target" "target/$target"
done
- name: Upload installer packages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Upload all installer packages
for installer in installers/*; do
gh release upload ${{ github.ref_name }} "$installer"
done
package-macos:
name: package-macos
runs-on: macos-latest
needs: create-release
strategy:
matrix:
include:
- arch: Intel
target: x86_64-apple-darwin
- arch: AppleSilicon
target: aarch64-apple-darwin
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install packaging tools
run: |
cargo install toml-cli
brew install create-dmg
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.target }}
path: artifacts
- name: Package for macOS
run: |
# Extract binary
tar -xzf "artifacts/rustnet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz"
# Get version and update plist
VERSION=$(toml get Cargo.toml package.version --raw)
sed -i'.bak' -e "s/0\.0\.0/${VERSION}/g" -e "s/fffffff/${GITHUB_SHA:0:7}/g" resources/packaging/macos/Info.plist
# Create app bundle
mkdir -p "Rustnet.app/Contents/"{MacOS,Resources}
cp resources/packaging/macos/Info.plist "Rustnet.app/Contents/"
cp resources/packaging/macos/graphics/rustnet.icns "Rustnet.app/Contents/Resources/"
cp "rustnet-${{ github.ref_name }}-${{ matrix.target }}/rustnet" "Rustnet.app/Contents/MacOS/"
cp resources/packaging/macos/wrapper.sh "Rustnet.app/Contents/MacOS/"
chmod +x "Rustnet.app/Contents/MacOS/"{rustnet,wrapper.sh}
# Create DMG
create-dmg \
--volname "Rustnet Installer" \
--background "resources/packaging/macos/graphics/dmg_bg.png" \
--window-pos 200 120 \
--window-size 900 450 \
--icon-size 100 \
--app-drop-link 620 240 \
--icon "Rustnet.app" 300 240 \
--hide-extension "Rustnet.app" \
"Rustnet_macOS_${{ matrix.arch }}.dmg" \
"Rustnet.app"
- name: Upload macOS package
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload ${{ github.ref_name }} "Rustnet_macOS_${{ matrix.arch }}.dmg"
package-windows:
name: package-windows
runs-on: windows-latest
needs: create-release
strategy:
matrix:
include:
- arch: 32-bit
target: i686-pc-windows-msvc
- arch: 64-bit
target: x86_64-pc-windows-msvc
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
shell: powershell
run: |
Write-Host "::group::WiX Toolset"
Invoke-WebRequest `
-Uri "https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip" `
-OutFile "$env:TEMP\wix-binaries.zip" -Verbose
Expand-Archive -LiteralPath "$env:TEMP\wix-binaries.zip" -DestinationPath "$env:TEMP\wix" -Verbose
Set-Item -Path env:Path -Value "$env:Path;$env:TEMP\wix"
Write-Host "::endgroup::"
- name: Install Rust and tools
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install packaging tools
run: cargo install cargo-wix
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.target }}
path: artifacts
- name: Package for Windows
shell: powershell
run: |
# Extract binary
Expand-Archive -LiteralPath "artifacts\rustnet-${{ github.ref_name }}-${{ matrix.target }}.zip" -DestinationPath .
New-Item -ItemType Directory -Path "target\${{ matrix.target }}\release" -Force
Move-Item -Path "rustnet-${{ github.ref_name }}-${{ matrix.target }}\rustnet.exe" -Destination "target\${{ matrix.target }}\release\"
# Create MSI package
cargo wix --no-build --nocapture --target ${{ matrix.target }}
Move-Item -Path "target\wix\rustnet-monitor*.msi" -Destination "Rustnet_Windows_${{ matrix.arch }}.msi"
- name: Upload Windows package
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload ${{ github.ref_name }} "Rustnet_Windows_${{ matrix.arch }}.msi"

477
Cargo.lock generated
View File

@@ -105,6 +105,15 @@ version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "arboard"
version = "3.6.1"
@@ -143,6 +152,15 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.17.0"
@@ -155,6 +173,12 @@ version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
@@ -167,6 +191,25 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "bzip2"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
dependencies = [
"bzip2-sys",
]
[[package]]
name = "bzip2-sys"
version = "0.1.13+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "camino"
version = "1.2.0"
@@ -220,6 +263,8 @@ version = "1.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
dependencies = [
"jobserver",
"libc",
"shlex",
]
@@ -246,7 +291,7 @@ dependencies = [
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
"windows-link 0.1.3",
]
[[package]]
@@ -281,6 +326,15 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.32"
@@ -299,6 +353,16 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "clap_mangen"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b4c3c54b30f0d9adcb47f25f61fcce35c4dd8916638c6b82fbd5f4fb4179e2"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "clipboard-win"
version = "5.4.0"
@@ -328,6 +392,12 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "constant_time_eq"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
[[package]]
name = "convert_case"
version = "0.7.1"
@@ -337,6 +407,16 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -352,6 +432,21 @@ dependencies = [
"libc",
]
[[package]]
name = "crc"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
dependencies = [
"crc-catalog",
]
[[package]]
name = "crc-catalog"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]]
name = "crc32fast"
version = "1.4.2"
@@ -519,6 +614,12 @@ dependencies = [
"parking_lot_core",
]
[[package]]
name = "deflate64"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
[[package]]
name = "deranged"
version = "0.4.0"
@@ -528,6 +629,17 @@ dependencies = [
"powerfmt",
]
[[package]]
name = "derive_arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_more"
version = "2.0.1"
@@ -549,6 +661,17 @@ dependencies = [
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "dispatch2"
version = "0.3.0"
@@ -559,6 +682,17 @@ dependencies = [
"objc2",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "dns-lookup"
version = "3.0.0"
@@ -666,6 +800,21 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -704,9 +853,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi",
"wasi 0.14.6+wasi-0.2.4",
"wasm-bindgen",
]
[[package]]
@@ -744,6 +895,25 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "http_req"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0122ab6637149482eb66b57288ac597bc7eb9859cbaa79dee62fa19a350df3d2"
dependencies = [
"native-tls",
"unicase",
]
[[package]]
name = "iana-time-zone"
version = "0.1.63"
@@ -787,6 +957,16 @@ dependencies = [
"tiff",
]
[[package]]
name = "indexmap"
version = "2.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
dependencies = [
"equivalent",
"hashbrown 0.15.4",
]
[[package]]
name = "indoc"
version = "2.0.6"
@@ -845,6 +1025,16 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.3",
"libc",
]
[[package]]
name = "jpeg-decoder"
version = "0.3.1"
@@ -968,6 +1158,27 @@ dependencies = [
"hashbrown 0.15.4",
]
[[package]]
name = "lzma-rs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
dependencies = [
"byteorder",
"crc",
]
[[package]]
name = "lzma-sys"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "memchr"
version = "2.7.4"
@@ -1005,6 +1216,23 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "native-tls"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "nix"
version = "0.30.1"
@@ -1145,6 +1373,50 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "openssl"
version = "0.10.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
dependencies = [
"bitflags 2.9.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-probe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "parking_lot"
version = "0.12.3"
@@ -1174,6 +1446,16 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
]
[[package]]
name = "pcap"
version = "2.3.0"
@@ -1388,6 +1670,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "roff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "rustix"
version = "0.38.44"
@@ -1424,10 +1712,13 @@ dependencies = [
"bytes",
"chrono",
"clap",
"clap_complete",
"clap_mangen",
"crossbeam",
"crossterm 0.29.0",
"dashmap",
"dns-lookup",
"http_req",
"libbpf-cargo",
"libbpf-rs",
"libbpf-sys",
@@ -1441,6 +1732,7 @@ dependencies = [
"ring",
"simple-logging",
"simplelog",
"zip",
]
[[package]]
@@ -1455,12 +1747,44 @@ version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "schannel"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
dependencies = [
"windows-sys 0.61.1",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.9.0",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "semver"
version = "1.0.27"
@@ -1514,6 +1838,17 @@ dependencies = [
"serde_core",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -1637,6 +1972,12 @@ dependencies = [
"syn",
]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.101"
@@ -1792,6 +2133,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unicase"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
[[package]]
name = "unicode-ident"
version = "1.0.18"
@@ -1839,6 +2186,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.5"
@@ -1982,7 +2335,7 @@ checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-link 0.1.3",
"windows-result",
"windows-strings",
]
@@ -2015,13 +2368,19 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
"windows-link 0.1.3",
]
[[package]]
@@ -2030,7 +2389,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-link",
"windows-link 0.1.3",
]
[[package]]
@@ -2073,6 +2432,15 @@ dependencies = [
"windows-targets 0.53.3",
]
[[package]]
name = "windows-sys"
version = "0.61.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f"
dependencies = [
"windows-link 0.2.0",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
@@ -2110,7 +2478,7 @@ version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link",
"windows-link 0.1.3",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
@@ -2311,3 +2679,102 @@ name = "x11rb-protocol"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
[[package]]
name = "xz2"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
dependencies = [
"lzma-sys",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zip"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50"
dependencies = [
"aes",
"arbitrary",
"bzip2",
"constant_time_eq",
"crc32fast",
"crossbeam-utils",
"deflate64",
"displaydoc",
"flate2",
"getrandom 0.3.3",
"hmac",
"indexmap",
"lzma-rs",
"memchr",
"pbkdf2",
"sha1",
"thiserror",
"time",
"xz2",
"zeroize",
"zopfli",
"zstd",
]
[[package]]
name = "zopfli"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
dependencies = [
"bumpalo",
"crc32fast",
"log",
"simd-adler32",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.16+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
dependencies = [
"cc",
"pkg-config",
]

View File

@@ -3,8 +3,8 @@ name = "rustnet-monitor"
version = "0.10.0"
authors = ["domcyrus"]
edition = "2024"
rust-version = "1.88.0" # Let-chains require Rust 1.88.0+
description = "A high-performance, cross-platform network monitoring terminal UI tool built with Rust"
rust-version = "1.88.0" # Let-chains require Rust 1.88.0+
description = "A cross-platform network monitoring terminal UI tool built with Rust"
repository = "https://github.com/domcyrus/rustnet"
homepage = "https://github.com/domcyrus/rustnet"
documentation = "https://docs.rs/rustnet-monitor"
@@ -48,9 +48,79 @@ libbpf-sys = { version = "1.4", optional = true }
bytes = { version = "1.5", optional = true }
libc = { version = "0.2", optional = true }
[build-dependencies]
anyhow = "1.0"
clap = { version = "4.5", features = ["derive"] }
clap_complete = "4.5"
clap_mangen = "0.2"
[target.'cfg(windows)'.build-dependencies]
http_req = "0.11"
zip = "2.1"
[target.'cfg(target_os = "linux")'.build-dependencies]
libbpf-cargo = "0.25"
[features]
default = []
ebpf = ["libbpf-rs", "libbpf-sys", "bytes", "libc"]
[package.metadata.deb]
maintainer = "domcyrus <domcyrus@example.com>"
copyright = "2024, domcyrus <domcyrus@example.com>"
license-file = ["LICENSE", "4"]
extended-description = """\
A real-time network monitoring terminal UI tool built with Rust.
Features:
- Real-time network monitoring with detailed state information
- Deep packet inspection for HTTP/HTTPS, DNS, SSH, and QUIC
- Connection lifecycle management with configurable timeouts
- Process identification and service name resolution
- Advanced filtering with vim/fzf-style search
- Multi-threaded processing for optimal performance
- Optional eBPF support for enhanced Linux performance
"""
depends = "libpcap0.8, libelf1, clang, llvm"
section = "net"
priority = "optional"
assets = [
[
"target/release/rustnet",
"usr/bin/",
"755",
],
[
"README.md",
"usr/share/doc/rustnet-monitor/",
"644",
],
[
"assets/services",
"usr/share/rustnet-monitor/",
"644",
],
[
"resources/packaging/linux/graphics/rustnet.png",
"usr/share/icons/hicolor/256x256/apps/",
"644",
],
[
"resources/packaging/linux/rustnet.desktop",
"usr/share/applications/",
"644",
],
]
conf-files = []
[package.metadata.generate-rpm]
assets = [
{ source = "target/release/rustnet", dest = "/usr/bin/rustnet", mode = "755" },
{ source = "README.md", dest = "/usr/share/doc/rustnet-monitor/README.md", mode = "644" },
{ source = "assets/services", dest = "/usr/share/rustnet-monitor/services", mode = "644" },
]
[package.metadata.generate-rpm.requires]
libpcap = "*"
libelf = "*"
clang = "*"
llvm = "*"

View File

@@ -87,7 +87,7 @@ Update the Homebrew formula file (`rustnet.rb` in your tap repository):
```ruby
class Rustnet < Formula
desc "High-performance network monitoring tool with TUI"
desc "Real-Time network monitoring tool with TUI"
homepage "https://github.com/domcyrus/homebrew-rustnet"
url "https://github.com/domcyrus/rustnet/archive/v0.2.0.tar.gz"
sha256 "a1b2c3d4e5f6..." # Replace with actual SHA256 from above

24
assets/rustnet.svg Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="128" height="128" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="RustNet Internet Logo">
<!-- Outer circle (globe outline) -->
<circle cx="512" cy="512" r="450" fill="none" stroke="#f97316" stroke-width="40"/>
<!-- Latitude lines -->
<ellipse cx="512" cy="512" rx="450" ry="300" fill="none" stroke="#38bdf8" stroke-width="16"/>
<ellipse cx="512" cy="512" rx="450" ry="220" fill="none" stroke="#38bdf8" stroke-width="16"/>
<ellipse cx="512" cy="512" rx="450" ry="120" fill="none" stroke="#38bdf8" stroke-width="12"/>
<!-- Longitude lines -->
<ellipse cx="512" cy="512" rx="300" ry="450" fill="none" stroke="#38bdf8" stroke-width="16"/>
<ellipse cx="512" cy="512" rx="220" ry="450" fill="none" stroke="#38bdf8" stroke-width="16"/>
<ellipse cx="512" cy="512" rx="120" ry="450" fill="none" stroke="#38bdf8" stroke-width="12"/>
<!-- Horizontal + vertical axis -->
<line x1="62" y1="512" x2="962" y2="512" stroke="#38bdf8" stroke-width="12"/>
<line x1="512" y1="62" x2="512" y2="962" stroke="#38bdf8" stroke-width="12"/>
<!-- Text in center -->
<text x="512" y="560" font-family="monospace" font-weight="bold" font-size="200" text-anchor="middle" fill="#f97316">
RustNet
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

111
build.rs
View File

@@ -1,12 +1,119 @@
use std::env;
use anyhow::Result;
use std::{env, fs::File, path::PathBuf};
fn main() -> Result<()> {
// Generate shell completions and manpage
generate_assets()?;
fn main() {
// Only compile eBPF programs on Linux when the feature is enabled
if cfg!(target_os = "linux") && env::var("CARGO_FEATURE_EBPF").is_ok() {
compile_ebpf_programs();
}
#[cfg(target_os = "windows")]
download_windows_npcap_sdk()?;
println!("cargo:rerun-if-changed=src/network/platform/linux_ebpf/programs/");
println!("cargo:rerun-if-changed=src/cli.rs");
Ok(())
}
include!("src/cli.rs");
fn generate_assets() -> Result<()> {
use clap::ValueEnum;
use clap_complete::Shell;
use clap_mangen::Man;
let mut cmd = build_cli();
// build into `RUSTNET_ASSET_DIR` with a fallback to `OUT_DIR`
let asset_dir: PathBuf = env::var_os("RUSTNET_ASSET_DIR")
.or_else(|| env::var_os("OUT_DIR"))
.ok_or_else(|| anyhow::anyhow!("OUT_DIR is unset"))?
.into();
// completion
for &shell in Shell::value_variants() {
clap_complete::generate_to(shell, &mut cmd, "rustnet", &asset_dir)?;
}
// manpage
let mut manpage_out = File::create(asset_dir.join("rustnet.1"))?;
let manpage = Man::new(cmd);
manpage.render(&mut manpage_out)?;
Ok(())
}
#[cfg(target_os = "windows")]
fn download_windows_npcap_sdk() -> Result<()> {
use std::{
fs,
io::{self, Write},
};
println!("cargo:rerun-if-changed=build.rs");
// get npcap SDK
const NPCAP_SDK: &str = "npcap-sdk-1.15.zip";
let npcap_sdk_download_url = format!("https://npcap.com/dist/{NPCAP_SDK}");
let cache_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?).join("target");
let npcap_sdk_cache_path = cache_dir.join(NPCAP_SDK);
let npcap_zip = match fs::read(&npcap_sdk_cache_path) {
// use cached
Ok(zip_data) => {
eprintln!("Found cached npcap SDK");
zip_data
}
// download SDK
Err(_) => {
eprintln!("Downloading npcap SDK");
// download
let mut zip_data = vec![];
let _res = http_req::request::get(npcap_sdk_download_url, &mut zip_data)?;
// write cache
fs::create_dir_all(cache_dir)?;
let mut cache = fs::File::create(npcap_sdk_cache_path)?;
cache.write_all(&zip_data)?;
zip_data
}
};
// extract DLL
let lib_path = if cfg!(target_arch = "aarch64") {
"Lib/ARM64/Packet.lib"
} else if cfg!(target_arch = "x86_64") {
"Lib/x64/Packet.lib"
} else if cfg!(target_arch = "x86") {
"Lib/Packet.lib"
} else {
panic!("Unsupported target!")
};
let mut archive = zip::ZipArchive::new(io::Cursor::new(npcap_zip))?;
let mut npcap_lib = archive.by_name(lib_path)?;
// write DLL
let lib_dir = PathBuf::from(env::var("OUT_DIR")?).join("npcap_sdk");
let lib_path = lib_dir.join("Packet.lib");
fs::create_dir_all(&lib_dir)?;
let mut lib_file = fs::File::create(lib_path)?;
io::copy(&mut npcap_lib, &mut lib_file)?;
println!(
"cargo:rustc-link-search=native={}",
lib_dir
.to_str()
.ok_or_else(|| anyhow::anyhow!("{lib_dir:?} is not valid UTF-8"))?
);
Ok(())
}
#[cfg(all(target_os = "linux", feature = "ebpf"))]

View File

@@ -0,0 +1,19 @@
app: rustnet
binpatch: true
ingredients:
dist: bookworm
sources:
- deb http://deb.debian.org/debian/ bookworm main
packages:
- libpcap0.8
- libelf1
debs:
- REPLACE_TAG
script:
- echo "Creating AppImage for rustnet..."
- cp resources/packaging/linux/graphics/rustnet.png usr/share/icons/hicolor/256x256/apps/rustnet.png
- cp resources/packaging/linux/rustnet.desktop usr/share/applications/rustnet.desktop
desktopintegration: rustnet

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Name=Rustnet
Comment=Real-Time network monitoring tool
Exec=rustnet
Icon=rustnet
Terminal=true
Categories=Network;Monitor;System;
Keywords=network;monitoring;packet;capture;terminal;
StartupNotify=false

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>wrapper.sh</string>
<key>CFBundleIconFile</key>
<string>rustnet.icns</string>
<key>CFBundleIdentifier</key>
<string>com.domcyrus.rustnet</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Rustnet</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.0.0</string>
<key>CFBundleVersion</key>
<string>fffffff</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>LSRequiresCarbon</key>
<false/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2025 domcyrus. All rights reserved.</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 KiB

View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Wrapper script for Rustnet macOS app
# This script launches the Rustnet binary in a terminal
# Get the directory where the app bundle is located
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# Check if we're running in Terminal already
if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] || [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
# Already in terminal, just run the binary
exec "$DIR/rustnet" "$@"
else
# Not in terminal, open Terminal and run the command
# This will open a new Terminal window with rustnet running
osascript -e "tell application \"Terminal\" to do script \"cd '$DIR' && ./rustnet; exit\""
fi

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@@ -0,0 +1,71 @@
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product
Id='*'
Name='Rustnet'
UpgradeCode='12345678-1234-1234-1234-123456789012'
Manufacturer='domcyrus'
Language='1033'
Codepage='1252'
Version='$(var.Version)'>
<Package Id='*'
Keywords='Installer'
Description='Rustnet Network Monitor Installer'
Manufacturer='domcyrus'
InstallerVersion='100'
Languages='1033'
Compressed='yes'
SummaryCodepage='1252'
/>
<Media Id='1' Cabinet='Sample.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
<Property Id='DiskPrompt' Value="Rustnet Installation [1]" />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder'>
<Directory Id='APPLICATIONROOTDIRECTORY' Name='Rustnet'>
<Component Id='MainExecutable' Guid='*'>
<File Id='RustnetExe'
Name='rustnet.exe'
DiskId='1'
Source='$(var.CargoTargetBinDir)\rustnet.exe'
KeyPath='yes'/>
</Component>
<Component Id='AppIcon' Guid='*'>
<File Id='RustnetIco'
Name='rustnet.ico'
DiskId='1'
Source='resources\packaging\windows\graphics\rustnet.ico'/>
</Component>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Rustnet">
<Component Id="ApplicationShortcut" Guid="*">
<Shortcut Id="ApplicationStartMenuShortcut"
Name="Rustnet"
Description="Cross-platform network monitoring tool"
Target="[APPLICATIONROOTDIRECTORY]rustnet.exe"
WorkingDirectory="APPLICATIONROOTDIRECTORY"
Icon="rustnet.ico"/>
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\Rustnet" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
</Directory>
<Icon Id="rustnet.ico" SourceFile="resources\packaging\windows\graphics\rustnet.ico" />
<Feature
Id='Complete'
Level='1'>
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='AppIcon' />
<ComponentRef Id='ApplicationShortcut' />
</Feature>
</Product>
</Wix>

View File

@@ -238,7 +238,7 @@ impl App {
}
// Log every 10000 packets or every 5 seconds
if packets_read % 10000 == 0
if packets_read.is_multiple_of(10000)
|| last_log.elapsed() > Duration::from_secs(5)
{
info!("Read {} packets so far", packets_read);
@@ -354,7 +354,9 @@ impl App {
.fetch_add(batch.len() as u64, Ordering::Relaxed);
// Log progress
if total_processed % 10000 == 0 || last_log.elapsed() > Duration::from_secs(5) {
if total_processed.is_multiple_of(10000)
|| last_log.elapsed() > Duration::from_secs(5)
{
debug!(
"Processor {}: {} packets processed ({} parsed)",
id, total_processed, parsed_count

46
src/cli.rs Normal file
View File

@@ -0,0 +1,46 @@
use clap::{Arg, Command};
pub fn build_cli() -> Command {
Command::new("rustnet")
.version(env!("CARGO_PKG_VERSION"))
.author("Network Monitor")
.about("Cross-platform network monitoring tool")
.arg(
Arg::new("interface")
.short('i')
.long("interface")
.value_name("INTERFACE")
.help("Network interface to monitor")
.required(false),
)
.arg(
Arg::new("no-localhost")
.long("no-localhost")
.help("Filter out localhost connections")
.action(clap::ArgAction::SetTrue),
)
.arg(
Arg::new("refresh-interval")
.short('r')
.long("refresh-interval")
.value_name("MILLISECONDS")
.help("UI refresh interval in milliseconds")
.value_parser(clap::value_parser!(u64))
.default_value("1000")
.required(false),
)
.arg(
Arg::new("no-dpi")
.long("no-dpi")
.help("Disable deep packet inspection")
.action(clap::ArgAction::SetTrue),
)
.arg(
Arg::new("log-level")
.short('l')
.long("log-level")
.value_name("LEVEL")
.help("Set the log level (if not provided, no logging will be enabled)")
.required(false),
)
}

View File

@@ -1,6 +1,6 @@
//! RustNet Monitor Library
//!
//! A high-performance, cross-platform network monitoring library built with Rust.
//! A cross-platform network monitoring library built with Rust.
pub mod app;
pub mod config;

View File

@@ -1,6 +1,5 @@
use anyhow::Result;
use arboard::Clipboard;
use clap::{Arg, Command};
use log::{LevelFilter, debug, error, info};
use ratatui::prelude::CrosstermBackend;
use simplelog::{Config as LogConfig, WriteLogger};
@@ -10,59 +9,20 @@ use std::path::Path;
use std::time::Duration;
mod app;
mod cli;
mod filter;
mod network;
mod ui;
fn main() -> Result<()> {
// Parse command line arguments
let matches = Command::new("rustnet")
.version(env!("CARGO_PKG_VERSION"))
.author("Network Monitor")
.about("Cross-platform network monitoring tool")
.arg(
Arg::new("interface")
.short('i')
.long("interface")
.value_name("INTERFACE")
.help("Network interface to monitor")
.required(false),
)
.arg(
Arg::new("no-localhost")
.long("no-localhost")
.help("Filter out localhost connections")
.action(clap::ArgAction::SetTrue),
)
.arg(
Arg::new("refresh-interval")
.short('r')
.long("refresh-interval")
.value_name("MILLISECONDS")
.help("UI refresh interval in milliseconds")
.value_parser(clap::value_parser!(u64))
.default_value("1000")
.required(false),
)
.arg(
Arg::new("no-dpi")
.long("no-dpi")
.help("Disable deep packet inspection")
.action(clap::ArgAction::SetTrue),
)
.arg(
Arg::new("log-level")
.short('l')
.long("log-level")
.value_name("LEVEL")
.help("Set the log level (if not provided, no logging will be enabled)")
.value_parser(clap::value_parser!(LevelFilter))
.required(false),
)
.get_matches();
let matches = cli::build_cli().get_matches();
// Set up logging only if log-level was provided
if let Some(log_level) = matches.get_one::<LevelFilter>("log-level") {
setup_logging(*log_level)?;
if let Some(log_level_str) = matches.get_one::<String>("log-level") {
let log_level = log_level_str
.parse::<LevelFilter>()
.map_err(|_| anyhow::anyhow!("Invalid log level: {}", log_level_str))?;
setup_logging(log_level)?;
}
info!("Starting RustNet Monitor");