netlink-sys-0.8.7/.cargo_vcs_info.json0000644000000001360000000000100133300ustar { "git": { "sha1": "a0693ba5e970d76b4668fce3b5849c556af44ca0" }, "path_in_vcs": "" }netlink-sys-0.8.7/.github/workflows/clippy-rustfmt.yml000064400000000000000000000015751046102023000212520ustar 00000000000000name: Rustfmt and clippy check on: pull_request: types: [opened, synchronize, reopened] push: branches: - main jobs: rustfmt_clippy: strategy: fail-fast: true name: Rustfmt and clippy check runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust Nightly run: | rustup override set nightly rustup update nightly rustup component add rustfmt clippy - name: rustfmt run: cargo fmt --all -- --check - name: clippy run: cargo clippy - name: clippy-tokio-socket run: cargo clippy --no-default-features --features tokio_socket - name: clippy-mio-socket run: cargo clippy --no-default-features --features mio_socket - name: clippy-smol-socket run: cargo clippy --no-default-features --features smol_socket netlink-sys-0.8.7/.github/workflows/license.yml000064400000000000000000000005201046102023000176570ustar 00000000000000name: license on: pull_request: types: [opened, synchronize, reopened] push: branches: - main jobs: check-license: name: Check License runs-on: ubuntu-latest timeout-minutes: 3 steps: - uses: actions/checkout@v3 - name: Check License Header uses: apache/skywalking-eyes@v0.3.0 netlink-sys-0.8.7/.github/workflows/main.yml000064400000000000000000000012251046102023000171640ustar 00000000000000name: CI on: pull_request: types: [opened, synchronize, reopened] push: branches: - main jobs: ci: name: CI (stable) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust Stable run: | rustup override set stable rustup update stable - name: Test with default feature run: cargo test - name: Test with mio feature run: cargo test --features mio_socket - name: Test with tokio feature run: cargo test --features tokio_socket - name: Test with smol_socket feature run: cargo test --features smol_socket netlink-sys-0.8.7/.gitignore000064400000000000000000000000411046102023000141030ustar 00000000000000Cargo.lock target vendor/ *.swp netlink-sys-0.8.7/.licenserc.yaml000064400000000000000000000004441046102023000150330ustar 00000000000000header: license: content: | SPDX-License-Identifier: MIT paths-ignore: - 'target' - '**/*.toml' - '**/*.lock' - '**/*.yml' - '**/*.md' - 'CHANGELOG' - 'LICENSE-MIT' - '.gitignore' - '.packit.yaml' - 'fedora/*.spec' comment: on-failure netlink-sys-0.8.7/.rustfmt.toml000064400000000000000000000001141046102023000145730ustar 00000000000000max_width = 80 wrap_comments = true reorder_imports = true edition = "2021" netlink-sys-0.8.7/CHANGELOG000064400000000000000000000014351046102023000133350ustar 00000000000000# Changelog ## [0.8.7] - 2024-12-10 ### Breaking Changes * N/A ### New Features * N/A ### Bug Fixes * N/A ### Other changes * upgrade dependencies ## [0.8.6] - 2024-04-03 ### Breaking Changes * N/A ### New Features * Support set `NETLINK_GET_STRICT_CHK`. (be6a7aa) * Support set and get socket receive buffer. (c4d7328) * Support set and get extended ACK. (008c65b) ### Bug Fixes * N/A ## [0.8.5] - 2023-03-05 ### Breaking Changes * N/A ### New Features * N/A ### Bug Fixes * Just a try for packit auto downstream release. (a9640d2) ## [0.8.4] - 2023-01-23 ### Breaking Changes * N/A ### New Features * N/A ### Bug Fixes * Move to standlone github repository. (8c1ee21) ## [0.8.3] - 2022-06-23 ### Breaking Changes * N/A ### New Features * N/A ### Bug Fixes * N/A netlink-sys-0.8.7/Cargo.lock0000644000000565510000000000100113170ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "anyhow" version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", "syn 1.0.109", ] [[package]] name = "async-channel" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-channel" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "slab", ] [[package]] name = "async-global-executor" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", "async-io", "async-lock", "blocking", "futures-lite", "once_cell", ] [[package]] name = "async-io" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", "rustix", "slab", "tracing", "windows-sys 0.59.0", ] [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-std" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", "async-io", "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-targets", ] [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blocking" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", "futures-lite", "piper", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "errno" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] [[package]] name = "event-listener-strategy" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener 5.3.1", "pin-project-lite", ] [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "futures" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "fastrand", "futures-core", "futures-io", "parking", "pin-project-lite", ] [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", ] [[package]] name = "futures-sink" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gloo-timers" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", ] [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "js-sys" version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ "log", ] [[package]] name = "libc" version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", ] [[package]] name = "mio" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", "wasi", "windows-sys 0.52.0", ] [[package]] name = "netlink-packet-audit" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8de479e785ec8c3dc692e430c437014ec840f8fa9a39edbe55e2faeb6ebffa" dependencies = [ "anyhow", "byteorder", "bytes", "log", "netlink-packet-core", "netlink-packet-utils", "netlink-proto", ] [[package]] name = "netlink-packet-core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" dependencies = [ "anyhow", "byteorder", "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-utils" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", "paste", "thiserror", ] [[package]] name = "netlink-proto" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys 0.8.6", "thiserror", "tokio", ] [[package]] name = "netlink-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ "bytes", "libc", "log", ] [[package]] name = "netlink-sys" version = "0.8.7" dependencies = [ "async-io", "async-std", "bytes", "futures", "libc", "log", "mio", "netlink-packet-audit", "tokio", ] [[package]] name = "object" version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pin-project-lite" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand", "futures-io", ] [[package]] name = "polling" version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix", "tracing", "windows-sys 0.59.0", ] [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "socket2" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", ] [[package]] name = "tokio" version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", "mio", "pin-project-lite", "socket2", "tokio-macros", "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", ] [[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "value-bag" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" netlink-sys-0.8.7/Cargo.toml0000644000000044260000000000100113340ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "netlink-sys" version = "0.8.7" authors = ["Corentin Henry "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "netlink sockets, with optional integration with tokio" homepage = "https://github.com/rust-netlink/netlink-sys" readme = "README.md" keywords = [ "netlink", "ip", "linux", ] license = "MIT" repository = "https://github.com/rust-netlink/netlink-sys" [lib] name = "netlink_sys" path = "src/lib.rs" [[example]] name = "audit_events" path = "examples/audit_events.rs" [[example]] name = "audit_events_async_std" path = "examples/audit_events_async_std.rs" required-features = ["smol_socket"] [[example]] name = "audit_events_tokio" path = "examples/audit_events_tokio.rs" required-features = ["tokio_socket"] [[example]] name = "audit_events_tokio_manual_thread_builder" path = "examples/audit_events_tokio_manual_thread_builder.rs" required-features = ["tokio_socket"] [dependencies.async-io] version = "2" optional = true [dependencies.bytes] version = "1.8" [dependencies.futures] version = "0.3.31" optional = true [dependencies.libc] version = "0.2.164" [dependencies.log] version = "0.4.8" [dependencies.mio] version = "1.0" features = [ "os-poll", "os-ext", ] optional = true [dependencies.tokio] version = "1.41.1" features = ["net"] optional = true default-features = false [dev-dependencies.async-std] version = "1.13" features = ["attributes"] [dev-dependencies.netlink-packet-audit] version = "0.4.1" [dev-dependencies.tokio] version = "1.0.1" features = [ "net", "macros", "rt-multi-thread", ] default-features = false [features] default = [] mio_socket = ["mio"] smol_socket = [ "async-io", "futures", ] tokio_socket = [ "tokio", "futures", ] netlink-sys-0.8.7/Cargo.toml.orig000064400000000000000000000027131046102023000150120ustar 00000000000000[package] authors = ["Corentin Henry "] name = "netlink-sys" version = "0.8.7" edition = "2018" homepage = "https://github.com/rust-netlink/netlink-sys" keywords = ["netlink", "ip", "linux"] license = "MIT" readme = "README.md" repository = "https://github.com/rust-netlink/netlink-sys" description = "netlink sockets, with optional integration with tokio" [dependencies] bytes = "1.8" libc = "0.2.164" log = "0.4.8" [dependencies.futures] optional = true version = "0.3.31" [dependencies.tokio] optional = true version = "1.41.1" default-features = false # We only depend on tokio for PollEvented features = ["net"] [dependencies.mio] optional = true version = "1.0" features = ["os-poll", "os-ext"] [dependencies.async-io] optional = true version = "2" [features] default = [] mio_socket = ["mio"] tokio_socket = ["tokio", "futures"] smol_socket = ["async-io", "futures"] [dev-dependencies] netlink-packet-audit = "0.4.1" [dev-dependencies.tokio] version = "1.0.1" default-features = false # We only depend on tokio for PollEvented features = ["net", "macros", "rt-multi-thread"] [dev-dependencies.async-std] version = "1.13" features = ["attributes"] [[example]] name = "audit_events" [[example]] name = "audit_events_tokio" required-features = ["tokio_socket"] [[example]] name = "audit_events_tokio_manual_thread_builder" required-features = ["tokio_socket"] [[example]] name = "audit_events_async_std" required-features = ["smol_socket"] netlink-sys-0.8.7/LICENSE-MIT000064400000000000000000000027731046102023000135650ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Distributions of all or part of the Software intended to be used by the recipients as they would use the unmodified Software, containing modifications that substantially alter, remove, or disable functionality of the Software, outside of the documented configuration mechanisms provided by the Software, shall be modified such that the Original Author's bug reporting email addresses and urls are either replaced with the contact information of the parties responsible for the changes, or removed entirely. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. netlink-sys-0.8.7/README.md000064400000000000000000000002531046102023000133770ustar 00000000000000# Rust netlink-sys crate The netlink_sys crate provides netlink sockets. Integration with mio and tokio is optional. [Rust crate Document](https://docs.rs/netlink-sys/) netlink-sys-0.8.7/examples/audit_events.rs000064400000000000000000000034621046102023000170030ustar 00000000000000// SPDX-License-Identifier: MIT // Build: // // ``` // cd netlink-sys // cargo build --example audit_events // ``` // // Run *as root*: // // ``` // ../target/debug/examples/audit_events // ``` use std::process; use netlink_packet_audit::{ AuditMessage, NetlinkBuffer, NetlinkMessage, StatusMessage, NLM_F_ACK, NLM_F_REQUEST, }; use netlink_sys::{protocols::NETLINK_AUDIT, Socket, SocketAddr}; pub const AUDIT_STATUS_ENABLED: u32 = 1; pub const AUDIT_STATUS_PID: u32 = 4; fn main() { let kernel_unicast: SocketAddr = SocketAddr::new(0, 0); let socket = Socket::new(NETLINK_AUDIT).unwrap(); let mut status = StatusMessage::new(); status.enabled = 1; status.pid = process::id(); status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID; let payload = AuditMessage::SetStatus(status); let mut nl_msg = NetlinkMessage::from(payload); nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK; nl_msg.finalize(); let mut buf = vec![0; 1024 * 8]; nl_msg.serialize(&mut buf[..nl_msg.buffer_len()]); socket .send_to(&buf[..nl_msg.buffer_len()], &kernel_unicast, 0) .unwrap(); let mut buf = vec![0; 1024 * 8]; loop { let (n, _addr) = socket.recv_from(&mut buf, 0).unwrap(); // This dance with the NetlinkBuffer should not be // necessary. It is here to work around a netlink bug. See: // https://github.com/mozilla/libaudit-go/issues/24 // https://github.com/linux-audit/audit-userspace/issues/78 { let mut nl_buf = NetlinkBuffer::new(&mut buf[0..n]); if n != nl_buf.length() as usize { nl_buf.set_length(n as u32); } } let parsed = NetlinkMessage::::deserialize(&buf[0..n]).unwrap(); println!("<<< {parsed:?}"); } } netlink-sys-0.8.7/examples/audit_events_async_std.rs000064400000000000000000000040111046102023000210410ustar 00000000000000// SPDX-License-Identifier: MIT // Build: // // ``` // cd netlink-sys // cargo build --example audit_events_async_std --features async_std_socket // ``` // // Run *as root*: // // ``` // ../target/debug/examples/audit_events_async_std // ``` use std::process; use netlink_packet_audit::{ AuditMessage, NetlinkBuffer, NetlinkMessage, StatusMessage, NLM_F_ACK, NLM_F_REQUEST, }; use netlink_sys::{ protocols::NETLINK_AUDIT, AsyncSocket, AsyncSocketExt, SmolSocket, SocketAddr, }; const AUDIT_STATUS_ENABLED: u32 = 1; const AUDIT_STATUS_PID: u32 = 4; #[async_std::main] async fn main() { let kernel_unicast: SocketAddr = SocketAddr::new(0, 0); let mut socket = SmolSocket::new(NETLINK_AUDIT).unwrap(); let mut status = StatusMessage::new(); status.enabled = 1; status.pid = process::id(); status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID; let payload = AuditMessage::SetStatus(status); let mut nl_msg = NetlinkMessage::from(payload); nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK; nl_msg.finalize(); let mut buf = vec![0; 1024 * 8]; nl_msg.serialize(&mut buf[..nl_msg.buffer_len()]); println!(">>> {:?}", nl_msg); socket .send_to(&buf[..nl_msg.buffer_len()], &kernel_unicast) .await .unwrap(); let mut buf = bytes::BytesMut::with_capacity(1024 * 8); loop { buf.clear(); let _addr = socket.recv_from(&mut buf).await.unwrap(); // This dance with the NetlinkBuffer should not be // necessary. It is here to work around a netlink bug. See: // https://github.com/mozilla/libaudit-go/issues/24 // https://github.com/linux-audit/audit-userspace/issues/78 { let n = buf.len(); let mut nl_buf = NetlinkBuffer::new(&mut buf); if n != nl_buf.length() as usize { nl_buf.set_length(n as u32); } } let parsed = NetlinkMessage::::deserialize(&buf).unwrap(); println!("<<< {:?}", parsed); } } netlink-sys-0.8.7/examples/audit_events_tokio.rs000064400000000000000000000040451046102023000202060ustar 00000000000000// SPDX-License-Identifier: MIT // Build: // // ``` // cd netlink-sys // cargo build --example audit_events_async --features tokio_socket // ``` // // Run *as root*: // // ``` // ../target/debug/examples/audit_events_async // ``` use std::process; use netlink_packet_audit::{ AuditMessage, NetlinkBuffer, NetlinkMessage, StatusMessage, NLM_F_ACK, NLM_F_REQUEST, }; use netlink_sys::{ protocols::NETLINK_AUDIT, AsyncSocket, AsyncSocketExt, SocketAddr, TokioSocket, }; const AUDIT_STATUS_ENABLED: u32 = 1; const AUDIT_STATUS_PID: u32 = 4; #[tokio::main] async fn main() -> Result<(), Box> { let kernel_unicast: SocketAddr = SocketAddr::new(0, 0); let mut socket = TokioSocket::new(NETLINK_AUDIT).unwrap(); let mut status = StatusMessage::new(); status.enabled = 1; status.pid = process::id(); status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID; let payload = AuditMessage::SetStatus(status); let mut nl_msg = NetlinkMessage::from(payload); nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK; nl_msg.finalize(); let mut buf = vec![0; 1024 * 8]; nl_msg.serialize(&mut buf[..nl_msg.buffer_len()]); println!(">>> {:?}", nl_msg); socket .send_to(&buf[..nl_msg.buffer_len()], &kernel_unicast) .await .unwrap(); let mut buf = bytes::BytesMut::with_capacity(1024 * 8); loop { buf.clear(); let _addr = socket.recv_from(&mut buf).await.unwrap(); // This dance with the NetlinkBuffer should not be // necessary. It is here to work around a netlink bug. See: // https://github.com/mozilla/libaudit-go/issues/24 // https://github.com/linux-audit/audit-userspace/issues/78 { let n = buf.len(); let mut nl_buf = NetlinkBuffer::new(&mut buf); if n != nl_buf.length() as usize { nl_buf.set_length(n as u32); } } let parsed = NetlinkMessage::::deserialize(&buf).unwrap(); println!("<<< {:?}", parsed); } } netlink-sys-0.8.7/examples/audit_events_tokio_manual_thread_builder.rs000064400000000000000000000007541046102023000246030ustar 00000000000000// SPDX-License-Identifier: MIT /* * This example shows the mimimal manual tokio initialization required to be * able to use netlink. */ use netlink_sys::{protocols::NETLINK_AUDIT, AsyncSocket, TokioSocket}; fn main() -> Result<(), String> { let rt = tokio::runtime::Builder::new_multi_thread() .enable_io() .build() .unwrap(); let future = async { TokioSocket::new(NETLINK_AUDIT).unwrap(); }; rt.handle().block_on(future); Ok(()) } netlink-sys-0.8.7/src/addr.rs000064400000000000000000000154061046102023000141750ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ fmt, hash::{Hash, Hasher}, mem, }; /// The address of a netlink socket /// /// A netlink address is made of two parts: the unicast address of the socket, /// called _port number_ or _PID_, and the multicast address called _group ID_. /// In this library, we've chosen to stick to the "port number" terminology, /// since PID can be confused with process ID. However, the netlink man page /// mostly uses PID. /// /// ## Port number /// /// Sockets in kernel space have 0 as a port number. For sockets opened by a /// user-space process, the port number can either be assigned by the process /// itself, or by the kernel. The only constraint is that this port number must /// be unique: two netlink sockets created by a given process must have a /// different port number. However, netlinks sockets created by different /// processes can have the same port number. /// /// ### Port number assigned by the kernel /// /// One way to set the port number is to let the kernel assign it, by calling /// [`Socket::bind`][bind] with a port number set to 0. The kernel will usually /// use the process ID as port number for the first netlink socket created by /// the process, which is why the socket port number is also called PID. For /// example: /// /// ```rust /// use std::process; /// use netlink_sys::{ /// protocols::NETLINK_ROUTE, /// SocketAddr, Socket, /// }; /// /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap(); /// // The first parameter is the port number. By setting it to 0 we ask the kernel to pick a port for us /// let mut addr = SocketAddr::new(0, 0); /// socket.bind(&addr).unwrap(); /// // Retrieve the socket address /// socket.get_address(&mut addr).unwrap(); /// // the socket port number should be equal to the process ID, but there is no guarantee /// println!("socket port number = {}, process ID = {}", addr.port_number(), process::id()); /// /// let mut socket2 = Socket::new(NETLINK_ROUTE).unwrap(); /// let mut addr2 = SocketAddr::new(0, 0); /// socket2.bind(&addr2).unwrap(); /// socket2.get_address(&mut addr2).unwrap(); /// // the unicast address picked by the kernel for the second socket should be different /// assert!(addr.port_number() != addr2.port_number()); /// ``` /// /// Note that it's a little tedious to create a socket address, call `bind` and /// then retrive the address with [`Socket::get_address`][get_addr]. To avoid /// this boilerplate you can use [`Socket::bind_auto`][bind_auto]: /// /// ```rust /// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; /// use std::process; /// /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap(); /// let addr = socket.bind_auto().unwrap(); /// println!("socket port number = {}", addr.port_number()); /// ``` /// /// ### Setting the port number manually /// /// The application can also pick the port number by calling Socket::bind with /// an address with a non-zero port number. However, it must ensure that this /// number is unique for each socket created. For instance: /// /// ```rust /// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; /// use std::process; /// /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap(); /// // set the socket port number to 2 /// let mut addr = SocketAddr::new(2, 0); /// socket.bind(&addr).unwrap(); /// // Retrieve the socket address /// socket.get_address(&mut addr).unwrap(); /// assert_eq!(2, addr.port_number()); /// /// // Creating a second socket with the same port number fails /// let mut socket2 = Socket::new(NETLINK_ROUTE).unwrap(); /// let mut addr2 = SocketAddr::new(2, 0); /// socket2.bind(&addr2).unwrap_err(); /// ``` /// /// [bind]: crate::Socket::bind /// [bind_auto]: crate::Socket::bind_auto /// [get_addr]: crate::Socket::get_address #[derive(Copy, Clone)] pub struct SocketAddr(pub(crate) libc::sockaddr_nl); impl Hash for SocketAddr { fn hash(&self, state: &mut H) { self.0.nl_family.hash(state); self.0.nl_pid.hash(state); self.0.nl_groups.hash(state); } } impl PartialEq for SocketAddr { fn eq(&self, other: &SocketAddr) -> bool { self.0.nl_family == other.0.nl_family && self.0.nl_pid == other.0.nl_pid && self.0.nl_groups == other.0.nl_groups } } impl fmt::Debug for SocketAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "SocketAddr(nl_family={}, nl_pid={}, nl_groups={})", self.0.nl_family, self.0.nl_pid, self.0.nl_groups ) } } impl Eq for SocketAddr {} impl fmt::Display for SocketAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "address family: {}, pid: {}, multicast groups: {})", self.0.nl_family, self.0.nl_pid, self.0.nl_groups ) } } impl SocketAddr { /// Create a new socket address for with th pub fn new(port_number: u32, multicast_groups: u32) -> Self { let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() }; addr.nl_family = libc::PF_NETLINK as libc::sa_family_t; addr.nl_pid = port_number; addr.nl_groups = multicast_groups; SocketAddr(addr) } /// Get the unicast address of this socket pub fn port_number(&self) -> u32 { self.0.nl_pid } /// Get the multicast groups of this socket pub fn multicast_groups(&self) -> u32 { self.0.nl_groups } pub(crate) fn as_raw(&self) -> (*const libc::sockaddr, libc::socklen_t) { let addr_ptr = &self.0 as *const libc::sockaddr_nl as *const libc::sockaddr; // \ / \ // / +---------------+---------------+ // +----------+---------+ | // | v // | create a raw pointer to the sockaddr_nl // | // v cast // *sockaddr_nl -> *sockaddr // // This kind of things seems to be pretty usual when using C APIs from // Rust. It could be written in a shorter way thank to type // inference: // // let addr_ptr: *const libc:sockaddr = &self.0 as *const _ as // *const _; // // But since this is my first time dealing with this kind of things I // chose the most explicit form. let addr_len = mem::size_of::() as libc::socklen_t; (addr_ptr, addr_len) } pub(crate) fn as_raw_mut( &mut self, ) -> (*mut libc::sockaddr, libc::socklen_t) { let addr_ptr = &mut self.0 as *mut libc::sockaddr_nl as *mut libc::sockaddr; let addr_len = mem::size_of::() as libc::socklen_t; (addr_ptr, addr_len) } } netlink-sys-0.8.7/src/async_socket.rs000064400000000000000000000035161046102023000157470ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ io, task::{Context, Poll}, }; use crate::{Socket, SocketAddr}; /// Trait to support different async backends pub trait AsyncSocket: Sized + Unpin { /// Access underyling [`Socket`] fn socket_ref(&self) -> &Socket; /// Mutable access to underyling [`Socket`] fn socket_mut(&mut self) -> &mut Socket; /// Wrapper for [`Socket::new`] fn new(protocol: isize) -> io::Result; /// Polling wrapper for [`Socket::send`] fn poll_send( &mut self, cx: &mut Context<'_>, buf: &[u8], ) -> Poll>; /// Polling wrapper for [`Socket::send_to`] fn poll_send_to( &mut self, cx: &mut Context<'_>, buf: &[u8], addr: &SocketAddr, ) -> Poll>; /// Polling wrapper for [`Socket::recv`] /// /// Passes 0 for flags, and ignores the returned length (the buffer will /// have advanced by the amount read). fn poll_recv( &mut self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> where B: bytes::BufMut; /// Polling wrapper for [`Socket::recv_from`] /// /// Passes 0 for flags, and ignores the returned length - just returns the /// address (the buffer will have advanced by the amount read). fn poll_recv_from( &mut self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> where B: bytes::BufMut; /// Polling wrapper for [`Socket::recv_from_full`] /// /// Passes 0 for flags, and ignores the returned length - just returns the /// address (the buffer will have advanced by the amount read). fn poll_recv_from_full( &mut self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>>; } netlink-sys-0.8.7/src/async_socket_ext.rs000064400000000000000000000070011046102023000166200ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ future::Future, io, pin::Pin, task::{Context, Poll}, }; use crate::{AsyncSocket, SocketAddr}; /// Support trait for [`AsyncSocket`] /// /// Provides awaitable variants of the poll functions from [`AsyncSocket`]. pub trait AsyncSocketExt: AsyncSocket { /// `async fn send(&mut self, buf: &[u8]) -> io::Result` fn send<'a, 'b>(&'a mut self, buf: &'b [u8]) -> PollSend<'a, 'b, Self> { PollSend { socket: self, buf } } /// `async fn send(&mut self, buf: &[u8]) -> io::Result` fn send_to<'a, 'b>( &'a mut self, buf: &'b [u8], addr: &'b SocketAddr, ) -> PollSendTo<'a, 'b, Self> { PollSendTo { socket: self, buf, addr, } } /// `async fn recv(&mut self, buf: &mut [u8]) -> io::Result<()>` fn recv<'a, 'b, B>( &'a mut self, buf: &'b mut B, ) -> PollRecv<'a, 'b, Self, B> where B: bytes::BufMut, { PollRecv { socket: self, buf } } /// `async fn recv(&mut self, buf: &mut [u8]) -> io::Result` fn recv_from<'a, 'b, B>( &'a mut self, buf: &'b mut B, ) -> PollRecvFrom<'a, 'b, Self, B> where B: bytes::BufMut, { PollRecvFrom { socket: self, buf } } /// `async fn recrecv_from_full(&mut self) -> io::Result<(Vec, /// SocketAddr)>` fn recv_from_full(&mut self) -> PollRecvFromFull<'_, Self> { PollRecvFromFull { socket: self } } } impl AsyncSocketExt for S {} pub struct PollSend<'a, 'b, S> { socket: &'a mut S, buf: &'b [u8], } impl Future for PollSend<'_, '_, S> where S: AsyncSocket, { type Output = io::Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this: &mut Self = Pin::into_inner(self); this.socket.poll_send(cx, this.buf) } } pub struct PollSendTo<'a, 'b, S> { socket: &'a mut S, buf: &'b [u8], addr: &'b SocketAddr, } impl Future for PollSendTo<'_, '_, S> where S: AsyncSocket, { type Output = io::Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this: &mut Self = Pin::into_inner(self); this.socket.poll_send_to(cx, this.buf, this.addr) } } pub struct PollRecv<'a, 'b, S, B> { socket: &'a mut S, buf: &'b mut B, } impl Future for PollRecv<'_, '_, S, B> where S: AsyncSocket, B: bytes::BufMut, { type Output = io::Result<()>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this: &mut Self = Pin::into_inner(self); this.socket.poll_recv(cx, this.buf) } } pub struct PollRecvFrom<'a, 'b, S, B> { socket: &'a mut S, buf: &'b mut B, } impl Future for PollRecvFrom<'_, '_, S, B> where S: AsyncSocket, B: bytes::BufMut, { type Output = io::Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this: &mut Self = Pin::into_inner(self); this.socket.poll_recv_from(cx, this.buf) } } pub struct PollRecvFromFull<'a, S> { socket: &'a mut S, } impl Future for PollRecvFromFull<'_, S> where S: AsyncSocket, { type Output = io::Result<(Vec, SocketAddr)>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this: &mut Self = Pin::into_inner(self); this.socket.poll_recv_from_full(cx) } } netlink-sys-0.8.7/src/constants.rs000064400000000000000000000117721046102023000153010ustar 00000000000000// SPDX-License-Identifier: MIT //! This module provides a lot of netlink constants for various protocol. As we //! add support for the various protocols, these constants will be moved to //! their own crate. use libc::c_int as int; /// Receives routing and link updates and may be used to modify the routing /// tables (both IPv4 and IPv6), IP addresses, link parameters, neighbor setups, /// queueing disciplines, traffic classes and packet classifiers (see /// rtnetlink(7)). pub const NETLINK_ROUTE: isize = 0; pub const NETLINK_UNUSED: isize = 1; /// Reserved for user-mode socket protocols. pub const NETLINK_USERSOCK: isize = 2; /// Transport IPv4 packets from netfilter to user space. Used by /// ip_queue kernel module. After a long period of being declared obsolete (in /// favor of the more advanced nfnetlink_queue feature), it was removed in /// Linux 3.5. pub const NETLINK_FIREWALL: isize = 3; /// Query information about sockets of various protocol families from the kernel /// (see sock_diag(7)). pub const NETLINK_SOCK_DIAG: isize = 4; /// Netfilter/iptables ULOG. pub const NETLINK_NFLOG: isize = 5; /// IPsec. pub const NETLINK_XFRM: isize = 6; /// SELinux event notifications. pub const NETLINK_SELINUX: isize = 7; /// Open-iSCSI. pub const NETLINK_ISCSI: isize = 8; /// Auditing. pub const NETLINK_AUDIT: isize = 9; /// Access to FIB lookup from user space. pub const NETLINK_FIB_LOOKUP: isize = 10; /// Kernel connector. See `Documentation/connector/*` in the Linux kernel source /// tree for further information. pub const NETLINK_CONNECTOR: isize = 11; /// Netfilter subsystem. pub const NETLINK_NETFILTER: isize = 12; /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue /// kernel module. pub const NETLINK_IP6_FW: isize = 13; /// DECnet routing messages. pub const NETLINK_DNRTMSG: isize = 14; /// Kernel messages to user space. pub const NETLINK_KOBJECT_UEVENT: isize = 15; /// Generic netlink family for simplified netlink usage. pub const NETLINK_GENERIC: isize = 16; /// SCSI transpots pub const NETLINK_SCSITRANSPORT: isize = 18; pub const NETLINK_ECRYPTFS: isize = 19; /// Infiniband RDMA. pub const NETLINK_RDMA: isize = 20; /// Netlink interface to request information about ciphers registered with the /// kernel crypto API as well as allow configuration of the kernel crypto API. pub const NETLINK_CRYPTO: isize = 21; pub const TCA_ROOT_UNSPEC: int = 0; pub const TCA_ROOT_TAB: int = 1; pub const TCA_ROOT_FLAGS: int = 2; pub const TCA_ROOT_COUNT: int = 3; pub const TCA_ROOT_TIME_DELTA: int = 4; pub const EM_NONE: u32 = 0; pub const EM_M32: u32 = 1; pub const EM_SPARC: u32 = 2; pub const EM_386: u32 = 3; pub const EM_68K: u32 = 4; pub const EM_88K: u32 = 5; pub const EM_486: u32 = 6; pub const EM_860: u32 = 7; pub const EM_MIPS: u32 = 8; pub const EM_MIPS_RS3_LE: u32 = 10; pub const EM_MIPS_RS4_BE: u32 = 10; pub const EM_PARISC: u32 = 15; pub const EM_SPARC32PLUS: u32 = 18; pub const EM_PPC: u32 = 20; pub const EM_PPC64: u32 = 21; pub const EM_SPU: u32 = 23; pub const EM_ARM: u32 = 40; pub const EM_SH: u32 = 42; pub const EM_SPARCV9: u32 = 43; pub const EM_H8_300: u32 = 46; pub const EM_IA_64: u32 = 50; pub const EM_X86_64: u32 = 62; pub const EM_S390: u32 = 22; pub const EM_CRIS: u32 = 76; pub const EM_M32R: u32 = 88; pub const EM_MN10300: u32 = 89; pub const EM_OPENRISC: u32 = 92; pub const EM_BLACKFIN: u32 = 106; pub const EM_ALTERA_NIOS2: u32 = 113; pub const EM_TI_C6000: u32 = 140; pub const EM_AARCH64: u32 = 183; pub const EM_TILEPRO: u32 = 188; pub const EM_MICROBLAZE: u32 = 189; pub const EM_TILEGX: u32 = 191; pub const EM_BPF: u32 = 247; pub const EM_FRV: u32 = 21569; pub const EM_ALPHA: u32 = 36902; pub const EM_CYGNUS_M32R: u32 = 36929; pub const EM_S390_OLD: u32 = 41872; pub const EM_CYGNUS_MN10300: u32 = 48879; pub const NLMSGERR_ATTR_UNUSED: int = 0; pub const NLMSGERR_ATTR_MSG: int = 1; pub const NLMSGERR_ATTR_OFFS: int = 2; pub const NLMSGERR_ATTR_COOKIE: int = 3; pub const NLMSGERR_ATTR_MAX: int = 3; pub const NL_MMAP_STATUS_UNUSED: int = 0; pub const NL_MMAP_STATUS_RESERVED: int = 1; pub const NL_MMAP_STATUS_VALID: int = 2; pub const NL_MMAP_STATUS_COPY: int = 3; pub const NL_MMAP_STATUS_SKIP: int = 4; pub const NETLINK_UNCONNECTED: int = 0; pub const NETLINK_CONNECTED: int = 1; pub const __BITS_PER_LONG: int = 64; pub const __FD_SETSIZE: int = 1024; pub const SI_LOAD_SHIFT: int = 16; pub const _K_SS_MAXSIZE: int = 128; pub const NETLINK_SMC: int = 22; pub const NETLINK_INET_DIAG: int = 4; pub const MAX_LINKS: int = 32; pub const NLMSG_MIN_TYPE: int = 16; pub const NETLINK_ADD_MEMBERSHIP: int = 1; pub const NETLINK_DROP_MEMBERSHIP: int = 2; pub const NETLINK_PKTINFO: int = 3; pub const NETLINK_BROADCAST_ERROR: int = 4; pub const NETLINK_NO_ENOBUFS: int = 5; pub const NETLINK_RX_RING: int = 6; pub const NETLINK_TX_RING: int = 7; pub const NETLINK_LISTEN_ALL_NSID: int = 8; pub const NETLINK_LIST_MEMBERSHIPS: int = 9; pub const NETLINK_CAP_ACK: int = 10; pub const NETLINK_EXT_ACK: int = 11; pub const NL_MMAP_MSG_ALIGNMENT: int = 4; pub const NET_MAJOR: int = 36; netlink-sys-0.8.7/src/lib.rs000064400000000000000000000017571046102023000140350ustar 00000000000000// SPDX-License-Identifier: MIT pub mod constants; pub mod protocols { pub use super::constants::{ NETLINK_AUDIT, NETLINK_CONNECTOR, NETLINK_CRYPTO, NETLINK_DNRTMSG, NETLINK_ECRYPTFS, NETLINK_FIB_LOOKUP, NETLINK_FIREWALL, NETLINK_GENERIC, NETLINK_IP6_FW, NETLINK_ISCSI, NETLINK_KOBJECT_UEVENT, NETLINK_NETFILTER, NETLINK_NFLOG, NETLINK_RDMA, NETLINK_ROUTE, NETLINK_SCSITRANSPORT, NETLINK_SELINUX, NETLINK_SOCK_DIAG, NETLINK_UNUSED, NETLINK_USERSOCK, NETLINK_XFRM, }; } mod socket; pub use self::socket::Socket; mod addr; pub use self::addr::SocketAddr; mod async_socket; pub use self::async_socket::AsyncSocket; pub mod async_socket_ext; pub use self::async_socket_ext::AsyncSocketExt; #[cfg(feature = "tokio_socket")] mod tokio; #[cfg(feature = "tokio_socket")] pub use self::tokio::TokioSocket; #[cfg(feature = "smol_socket")] mod smol; #[cfg(feature = "smol_socket")] pub use self::smol::SmolSocket; #[cfg(feature = "mio_socket")] mod mio; netlink-sys-0.8.7/src/mio.rs000064400000000000000000000050611046102023000140430ustar 00000000000000// SPDX-License-Identifier: MIT use crate::Socket; use std::os::unix::io::AsRawFd; use mio::{event::Source, unix::SourceFd}; impl Source for Socket { fn register( &mut self, registry: &mio::Registry, token: mio::Token, interests: mio::Interest, ) -> std::io::Result<()> { let raw_fd = self.as_raw_fd(); SourceFd(&raw_fd).register(registry, token, interests) } fn reregister( &mut self, registry: &mio::Registry, token: mio::Token, interests: mio::Interest, ) -> std::io::Result<()> { let raw_fd = self.as_raw_fd(); SourceFd(&raw_fd).reregister(registry, token, interests) } fn deregister(&mut self, registry: &mio::Registry) -> std::io::Result<()> { let raw_fd = self.as_raw_fd(); SourceFd(&raw_fd).deregister(registry) } } #[cfg(test)] mod tests { use super::*; fn request_neighbour_dump(socket: &mut Socket) -> std::io::Result<()> { // Buffer generated from: // ``` // let mut neighbour_dump_request = NetlinkMessage { // header: NetlinkHeader { // flags: NLM_F_DUMP | NLM_F_REQUEST, // ..Default::default() // }, // payload: NetlinkPayload::from(RtnlMessage::GetNeighbour(NeighbourMessage::default())), // }; // ``` let buf = [ 28, 0, 0, 0, 30, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; socket.send(&buf[..], 0)?; Ok(()) } #[test] fn test_event_loop() -> Result<(), Box> { use crate::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; use mio::{Events, Interest, Poll, Token}; use std::time::Duration; let mut poll = Poll::new()?; let mut events = Events::with_capacity(128); let mut socket = Socket::new(NETLINK_ROUTE)?; socket.bind_auto()?; socket.connect(&SocketAddr::new(0, 0))?; poll.registry() .register(&mut socket, Token(1), Interest::READABLE)?; // Send neighbour query request_neighbour_dump(&mut socket)?; // Make sure that we got anything poll.poll(&mut events, Some(Duration::from_secs(1)))?; assert!(!events.is_empty()); // Make sure the we didn't get a thing after removing socket from loop poll.registry().deregister(&mut socket)?; poll.poll(&mut events, Some(Duration::from_secs(1)))?; assert!(events.is_empty()); Ok(()) } } netlink-sys-0.8.7/src/smol.rs000064400000000000000000000071261046102023000142350ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ io, os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}, task::{Context, Poll}, }; use async_io::Async; use futures::ready; use log::trace; use crate::{AsyncSocket, Socket, SocketAddr}; /// An I/O object representing a Netlink socket. pub struct SmolSocket(Async); impl FromRawFd for SmolSocket { unsafe fn from_raw_fd(fd: RawFd) -> Self { let socket = Socket::from_raw_fd(fd); socket.set_non_blocking(true).unwrap(); SmolSocket(Async::new(socket).unwrap()) } } impl AsRawFd for SmolSocket { fn as_raw_fd(&self) -> RawFd { self.0.get_ref().as_raw_fd() } } impl AsFd for SmolSocket { fn as_fd(&self) -> BorrowedFd<'_> { self.0.get_ref().as_fd() } } // async_io::Async<..>::{read,write}_with[_mut] functions try IO first, // and only register context if it would block. // replicate this in these poll functions: impl SmolSocket { fn poll_write_with( &mut self, cx: &mut Context<'_>, mut op: F, ) -> Poll> where F: FnMut(&mut Self) -> io::Result, { loop { match op(self) { Err(err) if err.kind() == io::ErrorKind::WouldBlock => {} res => return Poll::Ready(res), } // try again if writable now, otherwise come back later: ready!(self.0.poll_writable(cx))?; } } fn poll_read_with( &mut self, cx: &mut Context<'_>, mut op: F, ) -> Poll> where F: FnMut(&mut Self) -> io::Result, { loop { match op(self) { Err(err) if err.kind() == io::ErrorKind::WouldBlock => {} res => return Poll::Ready(res), } // try again if readable now, otherwise come back later: ready!(self.0.poll_readable(cx))?; } } } impl AsyncSocket for SmolSocket { fn socket_ref(&self) -> &Socket { self.0.get_ref() } /// Mutable access to underyling [`Socket`] fn socket_mut(&mut self) -> &mut Socket { unsafe { self.0.get_mut() } } fn new(protocol: isize) -> io::Result { let socket = Socket::new(protocol)?; Ok(Self(Async::new(socket)?)) } fn poll_send( &mut self, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { self.poll_write_with(cx, |this| this.socket_mut().send(buf, 0)) } fn poll_send_to( &mut self, cx: &mut Context<'_>, buf: &[u8], addr: &SocketAddr, ) -> Poll> { self.poll_write_with(cx, |this| this.socket_mut().send_to(buf, addr, 0)) } fn poll_recv( &mut self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> where B: bytes::BufMut, { self.poll_read_with(cx, |this| { this.socket_mut().recv(buf, 0).map(|_len| ()) }) } fn poll_recv_from( &mut self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> where B: bytes::BufMut, { self.poll_read_with(cx, |this| { let x = this.socket_mut().recv_from(buf, 0); trace!("poll_recv_from: {:?}", x); x.map(|(_len, addr)| addr) }) } fn poll_recv_from_full( &mut self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>> { self.poll_read_with(cx, |this| this.socket_mut().recv_from_full()) } } netlink-sys-0.8.7/src/socket.rs000064400000000000000000000607471046102023000145630ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ io::{Error, Result}, mem, os::{ fd::{AsFd, BorrowedFd, FromRawFd}, unix::io::{AsRawFd, RawFd}, }, }; use crate::SocketAddr; /// A netlink socket. /// /// # Example /// /// In this example we: /// /// 1. open a new socket /// 2. send a message to the kernel /// 3. read the reponse /// /// ```rust /// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; /// use std::process; /// /// // open a new socket for the NETLINK_ROUTE subsystem (see "man 7 rtnetlink") /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap(); /// // address of the remote peer we'll send a message to. This particular address is for the kernel /// let kernel_addr = SocketAddr::new(0, 0); /// // this is a valid message for listing the network links on the system /// let pkt = vec![ /// 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x03, 0xfd, 0xfe, 0x38, 0x5c, 0x00, 0x00, 0x00, /// 0x00, 0x00, 0x00, 0x00, 0x00, /// ]; /// // send the message to the kernel /// let n_sent = socket.send_to(&pkt[..], &kernel_addr, 0).unwrap(); /// assert_eq!(n_sent, pkt.len()); /// // buffer for receiving the response /// let mut buf = vec![0; 4096]; /// loop { /// // receive a datagram /// let (n_received, sender_addr) = socket.recv_from(&mut &mut buf[..], 0).unwrap(); /// assert_eq!(sender_addr, kernel_addr); /// println!("received datagram {:?}", &buf[..n_received]); /// if buf[4] == 2 && buf[5] == 0 { /// println!("the kernel responded with an error"); /// return; /// } /// if buf[4] == 3 && buf[5] == 0 { /// println!("end of dump"); /// return; /// } /// } /// ``` #[derive(Clone, Debug)] pub struct Socket(RawFd); impl AsRawFd for Socket { fn as_raw_fd(&self) -> RawFd { self.0 } } impl AsFd for Socket { fn as_fd(&self) -> BorrowedFd<'_> { unsafe { BorrowedFd::borrow_raw(self.0) } } } impl FromRawFd for Socket { unsafe fn from_raw_fd(fd: RawFd) -> Self { Socket(fd) } } impl Drop for Socket { fn drop(&mut self) { unsafe { libc::close(self.as_raw_fd()) }; } } impl Socket { /// Open a new socket for the given netlink subsystem. `protocol` must be /// one of the [`netlink_sys::protocols`][protos] constants. /// /// [protos]: crate::protocols pub fn new(protocol: isize) -> Result { let res = unsafe { libc::socket( libc::PF_NETLINK, libc::SOCK_DGRAM | libc::SOCK_CLOEXEC, protocol as libc::c_int, ) }; if res < 0 { return Err(Error::last_os_error()); } Ok(Socket(res)) } /// Bind the socket to the given address pub fn bind(&mut self, addr: &SocketAddr) -> Result<()> { let (addr_ptr, addr_len) = addr.as_raw(); let res = unsafe { libc::bind(self.as_raw_fd(), addr_ptr, addr_len) }; if res < 0 { return Err(Error::last_os_error()); } Ok(()) } /// Bind the socket to an address assigned by the kernel, and return that /// address. pub fn bind_auto(&mut self) -> Result { let mut addr = SocketAddr::new(0, 0); self.bind(&addr)?; self.get_address(&mut addr)?; Ok(addr) } /// Get the socket address pub fn get_address(&self, addr: &mut SocketAddr) -> Result<()> { let (addr_ptr, mut addr_len) = addr.as_raw_mut(); let addr_len_copy = addr_len; let addr_len_ptr = &mut addr_len as *mut libc::socklen_t; let res = unsafe { libc::getsockname(self.as_raw_fd(), addr_ptr, addr_len_ptr) }; if res < 0 { return Err(Error::last_os_error()); } assert_eq!(addr_len, addr_len_copy); Ok(()) } // when building with --features smol we don't need this #[allow(dead_code)] /// Make this socket non-blocking pub fn set_non_blocking(&self, non_blocking: bool) -> Result<()> { let mut non_blocking = non_blocking as libc::c_int; let res = unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut non_blocking) }; if res < 0 { return Err(Error::last_os_error()); } Ok(()) } /// Connect the socket to the given address. Netlink is a connection-less /// protocol, so a socket can communicate with multiple peers with the /// [`Socket::send_to`] and [`Socket::recv_from`] methods. However, if the /// socket only needs to communicate with one peer, it is convenient not /// to have to bother with the peer address. This is what `connect` is /// for. After calling `connect`, [`Socket::send`] and [`Socket::recv`] /// respectively send and receive datagrams to and from `remote_addr`. /// /// # Examples /// /// In this example we: /// /// 1. open a socket /// 2. connect it to the kernel with [`Socket::connect`] /// 3. send a request to the kernel with [`Socket::send`] /// 4. read the response (which can span over several messages) /// [`Socket::recv`] /// /// ```rust /// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; /// use std::process; /// /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap(); /// let _ = socket.bind_auto().unwrap(); /// let kernel_addr = SocketAddr::new(0, 0); /// socket.connect(&kernel_addr).unwrap(); /// // This is a valid message for listing the network links on the system /// let msg = vec![ /// 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x03, 0xfd, 0xfe, 0x38, 0x5c, 0x00, 0x00, 0x00, /// 0x00, 0x00, 0x00, 0x00, 0x00, /// ]; /// let n_sent = socket.send(&msg[..], 0).unwrap(); /// assert_eq!(n_sent, msg.len()); /// // buffer for receiving the response /// let mut buf = vec![0; 4096]; /// loop { /// let mut n_received = socket.recv(&mut &mut buf[..], 0).unwrap(); /// println!("received {:?}", &buf[..n_received]); /// if buf[4] == 2 && buf[5] == 0 { /// println!("the kernel responded with an error"); /// return; /// } /// if buf[4] == 3 && buf[5] == 0 { /// println!("end of dump"); /// return; /// } /// } /// ``` pub fn connect(&self, remote_addr: &SocketAddr) -> Result<()> { // FIXME: // // Event though for SOCK_DGRAM sockets there's no IO, if our socket is // non-blocking, connect() might return EINPROGRESS. In theory, // the right way to treat EINPROGRESS would be to ignore the // error, and let the user poll the socket to check when it becomes // writable, indicating that the connection succeeded. The code already // exists in mio for TcpStream: // // > pub fn connect(stream: net::TcpStream, addr: &SocketAddr) -> // > io::Result { // > set_non_block(stream.as_raw_fd())?; // > match stream.connect(addr) { // > Ok(..) => {} // > Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} // > Err(e) => return Err(e), // > } // > Ok(TcpStream { inner: stream }) // > } // // In practice, since the connection does not require any IO for // SOCK_DGRAM sockets, it almost never returns EINPROGRESS and // so for now, we just return whatever libc::connect returns. If // it returns EINPROGRESS, the caller will have to handle the error // themself // // Refs: // // - https://stackoverflow.com/a/14046386/1836144 // - https://lists.isc.org/pipermail/bind-users/2009-August/077527.html let (addr, addr_len) = remote_addr.as_raw(); let res = unsafe { libc::connect(self.as_raw_fd(), addr, addr_len) }; if res < 0 { return Err(Error::last_os_error()); } Ok(()) } // Most of the comments in this method come from a discussion on rust users // forum. [thread]: https://users.rust-lang.org/t/help-understanding-libc-call/17308/9 // /// Read a datagram from the socket and return the number of bytes that have /// been read and the address of the sender. The data being read is /// copied into `buf`. If `buf` is too small, the datagram is truncated. The /// supported flags are the `MSG_*` described in `man 2 recvmsg` /// /// # Warning /// /// In datagram oriented protocols, `recv` and `recvfrom` receive normally /// only ONE datagram, but this seems not to be always true for netlink /// sockets: with some protocols like `NETLINK_AUDIT`, multiple netlink /// packets can be read with a single call. pub fn recv_from( &self, buf: &mut B, flags: libc::c_int, ) -> Result<(usize, SocketAddr)> where B: bytes::BufMut, { // Create an empty storage for the address. Note that Rust standard // library create a sockaddr_storage so that it works for any // address family, but here, we already know that we'll have a // Netlink address, so we can create the appropriate storage. let mut addr = unsafe { mem::zeroed::() }; // recvfrom takes a *sockaddr as parameter so that it can accept any // kind of address storage, so we need to create such a pointer // for the sockaddr_nl we just initialized. // // Create a raw pointer to Cast our raw // pointer to a our storage. We cannot // generic pointer to *sockaddr pass it to // recvfrom yet. that recvfrom can use // ^ ^ // | | // +--------------+---------------+ +---------+--------+ // / \ / // \ let addr_ptr = &mut addr as *mut libc::sockaddr_nl as *mut libc::sockaddr; // Why do we need to pass the address length? We're passing a generic // *sockaddr to recvfrom. Somehow recvfrom needs to make sure // that the address of the received packet would fit into the // actual type that is behind *sockaddr: it could be a sockaddr_nl but // also a sockaddr_in, a sockaddr_in6, or even the generic // sockaddr_storage that can store any address. let mut addrlen = mem::size_of_val(&addr); // recvfrom does not take the address length by value (see [thread]), so // we need to create a pointer to it. let addrlen_ptr = &mut addrlen as *mut usize as *mut libc::socklen_t; let chunk = buf.chunk_mut(); // Cast the *mut u8 into *mut void. // This is equivalent to casting a *char into *void // See [thread] // ^ // Create a *mut u8 | // ^ | // | | // +------+-------+ +--------+-------+ // / \ / \ let buf_ptr = chunk.as_mut_ptr() as *mut libc::c_void; let buf_len = chunk.len() as libc::size_t; let res = unsafe { libc::recvfrom( self.as_raw_fd(), buf_ptr, buf_len, flags, addr_ptr, addrlen_ptr, ) }; if res < 0 { return Err(Error::last_os_error()); } else { // with `MSG_TRUNC` `res` might exceed `buf_len` let written = std::cmp::min(buf_len, res as usize); unsafe { buf.advance_mut(written); } } Ok((res as usize, SocketAddr(addr))) } /// For a connected socket, `recv` reads a datagram from the socket. The /// sender is the remote peer the socket is connected to (see /// [`Socket::connect`]). See also [`Socket::recv_from`] pub fn recv(&self, buf: &mut B, flags: libc::c_int) -> Result where B: bytes::BufMut, { let chunk = buf.chunk_mut(); let buf_ptr = chunk.as_mut_ptr() as *mut libc::c_void; let buf_len = chunk.len() as libc::size_t; let res = unsafe { libc::recv(self.as_raw_fd(), buf_ptr, buf_len, flags) }; if res < 0 { return Err(Error::last_os_error()); } else { // with `MSG_TRUNC` `res` might exceed `buf_len` let written = std::cmp::min(buf_len, res as usize); unsafe { buf.advance_mut(written); } } Ok(res as usize) } /// Receive a full message. Unlike [`Socket::recv_from`], which truncates /// messages that exceed the length of the buffer passed as argument, /// this method always reads a whole message, no matter its size. pub fn recv_from_full(&self) -> Result<(Vec, SocketAddr)> { // Peek let mut buf: Vec = Vec::new(); let (peek_len, _) = self.recv_from(&mut buf, libc::MSG_PEEK | libc::MSG_TRUNC)?; // Receive buf.clear(); buf.reserve(peek_len); let (rlen, addr) = self.recv_from(&mut buf, 0)?; assert_eq!(rlen, peek_len); Ok((buf, addr)) } /// Send the given buffer `buf` to the remote peer with address `addr`. The /// supported flags are the `MSG_*` values documented in `man 2 send`. pub fn send_to( &self, buf: &[u8], addr: &SocketAddr, flags: libc::c_int, ) -> Result { let (addr_ptr, addr_len) = addr.as_raw(); let buf_ptr = buf.as_ptr() as *const libc::c_void; let buf_len = buf.len() as libc::size_t; let res = unsafe { libc::sendto( self.as_raw_fd(), buf_ptr, buf_len, flags, addr_ptr, addr_len, ) }; if res < 0 { return Err(Error::last_os_error()); } Ok(res as usize) } /// For a connected socket, `send` sends the given buffer `buf` to the /// remote peer the socket is connected to. See also [`Socket::connect`] /// and [`Socket::send_to`]. pub fn send(&self, buf: &[u8], flags: libc::c_int) -> Result { let buf_ptr = buf.as_ptr() as *const libc::c_void; let buf_len = buf.len() as libc::size_t; let res = unsafe { libc::send(self.as_raw_fd(), buf_ptr, buf_len, flags) }; if res < 0 { return Err(Error::last_os_error()); } Ok(res as usize) } pub fn set_pktinfo(&mut self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_PKTINFO, value, ) } pub fn get_pktinfo(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_PKTINFO, )?; Ok(res == 1) } pub fn add_membership(&mut self, group: u32) -> Result<()> { setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_ADD_MEMBERSHIP, group, ) } pub fn drop_membership(&mut self, group: u32) -> Result<()> { setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_DROP_MEMBERSHIP, group, ) } // pub fn list_membership(&self) -> Vec { // unimplemented!(); // // getsockopt won't be enough here, because we may need to perform 2 // calls, and because the // length of the list returned by // libc::getsockopt is returned by mutating the length // argument, // which our implementation of getsockopt forbids. } /// `NETLINK_BROADCAST_ERROR` (since Linux 2.6.30). When not set, /// `netlink_broadcast()` only reports `ESRCH` errors and silently /// ignore `NOBUFS` errors. pub fn set_broadcast_error(&mut self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_BROADCAST_ERROR, value, ) } pub fn get_broadcast_error(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_BROADCAST_ERROR, )?; Ok(res == 1) } /// `NETLINK_NO_ENOBUFS` (since Linux 2.6.30). This flag can be used by /// unicast and broadcast listeners to avoid receiving `ENOBUFS` errors. pub fn set_no_enobufs(&mut self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_NO_ENOBUFS, value, ) } pub fn get_no_enobufs(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_NO_ENOBUFS, )?; Ok(res == 1) } /// `NETLINK_LISTEN_ALL_NSID` (since Linux 4.2). When set, this socket will /// receive netlink notifications from all network namespaces that /// have an nsid assigned into the network namespace where the socket /// has been opened. The nsid is sent to user space via an ancillary /// data. pub fn set_listen_all_namespaces(&mut self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_LISTEN_ALL_NSID, value, ) } pub fn get_listen_all_namespaces(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_LISTEN_ALL_NSID, )?; Ok(res == 1) } /// `NETLINK_CAP_ACK` (since Linux 4.2). The kernel may fail to allocate the /// necessary room for the acknowledgment message back to user space. /// This option trims off the payload of the original netlink message. /// The netlink message header is still included, so the user can /// guess from the sequence number which message triggered the /// acknowledgment. pub fn set_cap_ack(&mut self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_CAP_ACK, value, ) } pub fn get_cap_ack(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_CAP_ACK, )?; Ok(res == 1) } /// `NETLINK_EXT_ACK` /// Extended ACK controls reporting of additional error/warning TLVs in /// NLMSG_ERROR and NLMSG_DONE messages. pub fn set_ext_ack(&mut self, value: bool) -> Result<()> { let value: libc::c_int = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_EXT_ACK, value, ) } pub fn get_ext_ack(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_EXT_ACK, )?; Ok(res == 1) } /// Sets socket receive buffer in bytes. /// The kernel doubles this value (to allow space for bookkeeping overhead), /// and this doubled value is returned by [get_rx_buf_sz].(see socket(7) /// The default value is set by the proc/sys/net/core/rmem_default file, and /// the maximum allowed value is set by the /proc/sys/net/core/rmem_max /// file. The minimum (doubled) value for this option is 256. pub fn set_rx_buf_sz(&self, size: T) -> Result<()> { setsockopt(self.as_raw_fd(), libc::SOL_SOCKET, libc::SO_RCVBUF, size) } /// Gets socket receive buffer in bytes pub fn get_rx_buf_sz(&self) -> Result { let res = getsockopt::( self.as_raw_fd(), libc::SOL_SOCKET, libc::SO_RCVBUF, )?; Ok(res as usize) } /// Set strict input checking(`NETLINK_GET_STRICT_CHK`) in netlink route /// protocol. By default, `NETLINK_GET_STRICT_CHK` is not enabled. pub fn set_netlink_get_strict_chk(&self, value: bool) -> Result<()> { let value: u32 = value.into(); setsockopt( self.as_raw_fd(), libc::SOL_NETLINK, libc::NETLINK_GET_STRICT_CHK, value, ) } } /// Wrapper around `getsockopt`: /// /// ```no_rust /// int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len); /// ``` pub(crate) fn getsockopt( fd: RawFd, level: libc::c_int, option: libc::c_int, ) -> Result { // Create storage for the options we're fetching let mut slot: T = unsafe { mem::zeroed() }; // Create a mutable raw pointer to the storage so that getsockopt can fill // the value let slot_ptr = &mut slot as *mut T as *mut libc::c_void; // Let getsockopt know how big our storage is let mut slot_len = mem::size_of::() as libc::socklen_t; // getsockopt takes a mutable pointer to the length, because for some // options like NETLINK_LIST_MEMBERSHIP where the option value is a list // with arbitrary length, getsockopt uses this parameter to signal how // big the storage needs to be. let slot_len_ptr = &mut slot_len as *mut libc::socklen_t; let res = unsafe { libc::getsockopt(fd, level, option, slot_ptr, slot_len_ptr) }; if res < 0 { return Err(Error::last_os_error()); } // Ignore the options that require the legnth to be set by getsockopt. // We'll deal with them individually. assert_eq!(slot_len as usize, mem::size_of::()); Ok(slot) } // adapted from rust standard library fn setsockopt( fd: RawFd, level: libc::c_int, option: libc::c_int, payload: T, ) -> Result<()> { let payload = &payload as *const T as *const libc::c_void; let payload_len = mem::size_of::() as libc::socklen_t; let res = unsafe { libc::setsockopt(fd, level, option, payload, payload_len) }; if res < 0 { return Err(Error::last_os_error()); } Ok(()) } #[cfg(test)] mod test { use super::*; use crate::protocols::NETLINK_ROUTE; #[test] fn new() { Socket::new(NETLINK_ROUTE).unwrap(); } #[test] fn connect() { let sock = Socket::new(NETLINK_ROUTE).unwrap(); sock.connect(&SocketAddr::new(0, 0)).unwrap(); } #[test] fn bind() { let mut sock = Socket::new(NETLINK_ROUTE).unwrap(); sock.bind(&SocketAddr::new(4321, 0)).unwrap(); } #[test] fn bind_auto() { let mut sock = Socket::new(NETLINK_ROUTE).unwrap(); let addr = sock.bind_auto().unwrap(); // make sure that the address we got from the kernel is there assert!(addr.port_number() != 0); } #[test] fn set_non_blocking() { let sock = Socket::new(NETLINK_ROUTE).unwrap(); sock.set_non_blocking(true).unwrap(); sock.set_non_blocking(false).unwrap(); } #[test] fn options() { let mut sock = Socket::new(NETLINK_ROUTE).unwrap(); sock.set_cap_ack(true).unwrap(); assert!(sock.get_cap_ack().unwrap()); sock.set_cap_ack(false).unwrap(); assert!(!sock.get_cap_ack().unwrap()); sock.set_no_enobufs(true).unwrap(); assert!(sock.get_no_enobufs().unwrap()); sock.set_no_enobufs(false).unwrap(); assert!(!sock.get_no_enobufs().unwrap()); sock.set_broadcast_error(true).unwrap(); assert!(sock.get_broadcast_error().unwrap()); sock.set_broadcast_error(false).unwrap(); assert!(!sock.get_broadcast_error().unwrap()); // FIXME: these require root permissions // sock.set_listen_all_namespaces(true).unwrap(); // assert!(sock.get_listen_all_namespaces().unwrap()); // sock.set_listen_all_namespaces(false).unwrap(); // assert!(!sock.get_listen_all_namespaces().unwrap()); } } netlink-sys-0.8.7/src/tokio.rs000064400000000000000000000106031046102023000144020ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ io, os::unix::io::{AsRawFd, FromRawFd, RawFd}, task::{Context, Poll}, }; use futures::ready; use log::trace; use tokio::io::unix::AsyncFd; use crate::{AsyncSocket, Socket, SocketAddr}; /// An I/O object representing a Netlink socket. pub struct TokioSocket(AsyncFd); impl FromRawFd for TokioSocket { unsafe fn from_raw_fd(fd: RawFd) -> Self { let socket = Socket::from_raw_fd(fd); socket.set_non_blocking(true).unwrap(); TokioSocket(AsyncFd::new(socket).unwrap()) } } impl AsRawFd for TokioSocket { fn as_raw_fd(&self) -> RawFd { self.0.get_ref().as_raw_fd() } } impl AsyncSocket for TokioSocket { fn socket_ref(&self) -> &Socket { self.0.get_ref() } /// Mutable access to underyling [`Socket`] fn socket_mut(&mut self) -> &mut Socket { self.0.get_mut() } fn new(protocol: isize) -> io::Result { let socket = Socket::new(protocol)?; socket.set_non_blocking(true)?; Ok(Self(AsyncFd::new(socket)?)) } fn poll_send( &mut self, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { loop { // Check if the socket it writable. If // AsyncFd::poll_write_ready returns NotReady, it will // already have arranged for the current task to be // notified when the socket becomes writable, so we can // just return Pending let mut guard = ready!(self.0.poll_write_ready(cx))?; match guard.try_io(|inner| inner.get_ref().send(buf, 0)) { Ok(x) => return Poll::Ready(x), Err(_would_block) => continue, } } } fn poll_send_to( &mut self, cx: &mut Context<'_>, buf: &[u8], addr: &SocketAddr, ) -> Poll> { loop { let mut guard = ready!(self.0.poll_write_ready(cx))?; match guard.try_io(|inner| inner.get_ref().send_to(buf, addr, 0)) { Ok(x) => return Poll::Ready(x), Err(_would_block) => continue, } } } fn poll_recv( &mut self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> where B: bytes::BufMut, { loop { // Check if the socket is readable. If not, // AsyncFd::poll_read_ready would have arranged for the // current task to be polled again when the socket becomes // readable, so we can just return Pending let mut guard = ready!(self.0.poll_read_ready(cx))?; match guard.try_io(|inner| inner.get_ref().recv(buf, 0)) { Ok(x) => return Poll::Ready(x.map(|_len| ())), Err(_would_block) => continue, } } } fn poll_recv_from( &mut self, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> where B: bytes::BufMut, { loop { trace!("poll_recv_from called"); let mut guard = ready!(self.0.poll_read_ready(cx))?; trace!("poll_recv_from socket is ready for reading"); match guard.try_io(|inner| inner.get_ref().recv_from(buf, 0)) { Ok(x) => { trace!("poll_recv_from {:?} bytes read", x); return Poll::Ready(x.map(|(_len, addr)| addr)); } Err(_would_block) => { trace!("poll_recv_from socket would block"); continue; } } } } fn poll_recv_from_full( &mut self, cx: &mut Context<'_>, ) -> Poll, SocketAddr)>> { loop { trace!("poll_recv_from_full called"); let mut guard = ready!(self.0.poll_read_ready(cx))?; trace!("poll_recv_from_full socket is ready for reading"); match guard.try_io(|inner| inner.get_ref().recv_from_full()) { Ok(x) => { trace!("poll_recv_from_full {:?} bytes read", x); return Poll::Ready(x); } Err(_would_block) => { trace!("poll_recv_from_full socket would block"); continue; } } } } }