diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..fd74d23 --- /dev/null +++ b/.github/workflows/release.yml @@ -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" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index f50dc79..b2edb64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", +] diff --git a/Cargo.toml b/Cargo.toml index 39d464f..82c7ced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 " +copyright = "2024, domcyrus " +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 = "*" diff --git a/RELEASE.md b/RELEASE.md index 1eba338..5c26f26 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -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 diff --git a/assets/rustnet.svg b/assets/rustnet.svg new file mode 100644 index 0000000..f22b8f7 --- /dev/null +++ b/assets/rustnet.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + RustNet + + diff --git a/build.rs b/build.rs index 2a9b324..904d2be 100644 --- a/build.rs +++ b/build.rs @@ -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"))] diff --git a/resources/packaging/linux/AppImage/rustnet.yml b/resources/packaging/linux/AppImage/rustnet.yml new file mode 100644 index 0000000..d441640 --- /dev/null +++ b/resources/packaging/linux/AppImage/rustnet.yml @@ -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 diff --git a/resources/packaging/linux/graphics/rustnet.png b/resources/packaging/linux/graphics/rustnet.png new file mode 100644 index 0000000..7758d5b Binary files /dev/null and b/resources/packaging/linux/graphics/rustnet.png differ diff --git a/resources/packaging/linux/rustnet.desktop b/resources/packaging/linux/rustnet.desktop new file mode 100644 index 0000000..b57e562 --- /dev/null +++ b/resources/packaging/linux/rustnet.desktop @@ -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 \ No newline at end of file diff --git a/resources/packaging/macos/Info.plist b/resources/packaging/macos/Info.plist new file mode 100644 index 0000000..2e3e81a --- /dev/null +++ b/resources/packaging/macos/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + wrapper.sh + CFBundleIconFile + rustnet.icns + CFBundleIdentifier + com.domcyrus.rustnet + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Rustnet + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.0 + CFBundleVersion + fffffff + LSApplicationCategoryType + public.app-category.developer-tools + LSMinimumSystemVersion + 10.13 + LSRequiresCarbon + + NSHumanReadableCopyright + Copyright © 2025 domcyrus. All rights reserved. + NSHighResolutionCapable + + + \ No newline at end of file diff --git a/resources/packaging/macos/graphics/dmg_bg.png b/resources/packaging/macos/graphics/dmg_bg.png new file mode 100644 index 0000000..c701477 Binary files /dev/null and b/resources/packaging/macos/graphics/dmg_bg.png differ diff --git a/resources/packaging/macos/graphics/rustnet.icns b/resources/packaging/macos/graphics/rustnet.icns new file mode 100644 index 0000000..ed0373d Binary files /dev/null and b/resources/packaging/macos/graphics/rustnet.icns differ diff --git a/resources/packaging/macos/graphics/rustnet.png b/resources/packaging/macos/graphics/rustnet.png new file mode 100644 index 0000000..ed8b12c Binary files /dev/null and b/resources/packaging/macos/graphics/rustnet.png differ diff --git a/resources/packaging/macos/wrapper.sh b/resources/packaging/macos/wrapper.sh new file mode 100644 index 0000000..6406bfa --- /dev/null +++ b/resources/packaging/macos/wrapper.sh @@ -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 \ No newline at end of file diff --git a/resources/packaging/windows/graphics/rustnet.ico b/resources/packaging/windows/graphics/rustnet.ico new file mode 100644 index 0000000..fd841c0 Binary files /dev/null and b/resources/packaging/windows/graphics/rustnet.ico differ diff --git a/resources/packaging/windows/wix/main.wxs b/resources/packaging/windows/wix/main.wxs new file mode 100644 index 0000000..d112d5b --- /dev/null +++ b/resources/packaging/windows/wix/main.wxs @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index e855880..c4b1c8a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -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 diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..5149f56 --- /dev/null +++ b/src/cli.rs @@ -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), + ) +} diff --git a/src/lib.rs b/src/lib.rs index f5353be..1abc56d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/main.rs b/src/main.rs index f160e80..5af2de7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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::("log-level") { - setup_logging(*log_level)?; + if let Some(log_level_str) = matches.get_one::("log-level") { + let log_level = log_level_str + .parse::() + .map_err(|_| anyhow::anyhow!("Invalid log level: {}", log_level_str))?; + setup_logging(log_level)?; } info!("Starting RustNet Monitor");