netlink-proto-0.11.2/.cargo_vcs_info.json0000644000000001360000000000100137220ustar { "git": { "sha1": "fb0bc8f7ca2618de1539969c1d4adb1ef10f5ee7" }, "path_in_vcs": "" }netlink-proto-0.11.2/.github/workflows/clippy-rustfmt.yml000064400000000000000000000012701046102023000216340ustar 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-tokio-socket run: cargo clippy - name: clippy-smol-socket run: cargo clippy --no-default-features --features smol_socket netlink-proto-0.11.2/.github/workflows/license.yml000064400000000000000000000005201046102023000202510ustar 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-proto-0.11.2/.github/workflows/main.yml000064400000000000000000000011021046102023000175500ustar 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 tokio feature run: cargo test --features tokio_socket - name: Test with smol_socket feature run: cargo test --features smol_socket netlink-proto-0.11.2/.gitignore000064400000000000000000000000411046102023000144750ustar 00000000000000Cargo.lock target vendor/ *.swp netlink-proto-0.11.2/.licenserc.yaml000064400000000000000000000003711046102023000154240ustar 00000000000000header: license: content: | SPDX-License-Identifier: MIT paths-ignore: - 'target' - '**/*.toml' - '**/*.lock' - '**/*.yml' - '**/*.md' - 'CHANGELOG' - 'LICENSE-MIT' - '.gitignore' comment: on-failure netlink-proto-0.11.2/.rustfmt.toml000064400000000000000000000001141046102023000151650ustar 00000000000000max_width = 80 wrap_comments = true reorder_imports = true edition = "2021" netlink-proto-0.11.2/CHANGELOG000064400000000000000000000010111046102023000137150ustar 00000000000000# Changelog ## [0.11.2] - 2023-01-28 ### Breaking changes - N/A ### New features - N/A ### Bug fixes - Check for closed unsolicited messages channel. (2e14c59) - Use latest netlink-packet-core 0.7.0. (55fb44f) ## [0.11.1] - 2023-01-28 ### Breaking changes - N/A ### New features - N/A ### Bug fixes - Cosmetic release to update crates.io. ## [0.11.0] - 2023-01-28 ### Breaking changes - Remove `netlink_proto::packet`, please use netlink_packet_core (4fa7411) ### New features - N/A ### Bug fixes - N/A netlink-proto-0.11.2/Cargo.lock0000644000000646010000000000100117040ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] [[package]] name = "anyhow" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[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", "futures-core", ] [[package]] name = "async-executor" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" dependencies = [ "async-lock", "async-task", "concurrent-queue", "fastrand", "futures-lite", "slab", ] [[package]] name = "async-global-executor" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ "async-channel", "async-executor", "async-io", "async-lock", "blocking", "futures-lite", "once_cell", ] [[package]] name = "async-io" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock", "autocfg", "cfg-if", "concurrent-queue", "futures-lite", "log", "parking", "polling", "rustix", "slab", "socket2", "waker-fn", ] [[package]] name = "async-lock" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" dependencies = [ "event-listener", ] [[package]] name = "async-std" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", "async-channel", "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.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "atomic-waker" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blocking" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ "async-channel", "async-lock", "async-task", "atomic-waker", "fastrand", "futures-lite", "log", ] [[package]] name = "bumpalo" version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[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.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] [[package]] name = "env_logger" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", "log", "regex", "termcolor", ] [[package]] name = "errno" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", "windows-sys", ] [[package]] name = "errno-dragonfly" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ "cc", "libc", ] [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "futures" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", "parking", "pin-project-lite", "waker-fn", ] [[package]] name = "futures-macro" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", "syn 2.0.24", ] [[package]] name = "futures-sink" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 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.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "gloo-timers" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", ] [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "hermit-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] [[package]] name = "io-lifetimes" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.2", "libc", "windows-sys", ] [[package]] name = "js-sys" version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "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.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "linux-raw-sys" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" dependencies = [ "value-bag", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "miniz_oxide" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", "windows-sys", ] [[package]] name = "netlink-packet-audit" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92a96b8bea15a94823ea3997b2dd8938fd53ca298719e6a68246903e6d96477" dependencies = [ "anyhow", "byteorder", "bytes", "log", "netlink-packet-core 0.5.0", "netlink-packet-utils", "netlink-proto 0.11.1", ] [[package]] name = "netlink-packet-core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5cf0b54effda4b91615c40ff0fd12d0d4c9a6e0f5116874f03941792ff535a" dependencies = [ "anyhow", "byteorder", "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-core" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" dependencies = [ "anyhow", "byteorder", "netlink-packet-utils", ] [[package]] name = "netlink-packet-route" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e07eaabf1668ec61d1dd6fcc2414e25b7b94e8e1f8e56e4e9a5c023ab18c440f" dependencies = [ "anyhow", "bitflags", "byteorder", "libc", "netlink-packet-core 0.5.0", "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.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26305d12193227ef7b8227e7d61ae4eaf174607f79bd8eeceff07aacaefde497" dependencies = [ "bytes", "futures", "log", "netlink-packet-core 0.5.0", "netlink-sys", "thiserror", "tokio", ] [[package]] name = "netlink-proto" version = "0.11.2" dependencies = [ "async-std", "bytes", "env_logger", "futures", "log", "netlink-packet-audit", "netlink-packet-core 0.7.0", "netlink-packet-route", "netlink-sys", "thiserror", "tokio", ] [[package]] name = "netlink-sys" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" dependencies = [ "async-io", "bytes", "futures", "libc", "log", "tokio", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi 0.3.2", "libc", ] [[package]] name = "object" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "parking" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" [[package]] name = "paste" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "pin-project-lite" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "polling" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags", "cfg-if", "concurrent-queue", "libc", "log", "pin-project-lite", "windows-sys", ] [[package]] name = "proc-macro2" version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "slab" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] [[package]] name = "socket2" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", ] [[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.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36ccaf716a23c35ff908f91c971a86a9a71af5998c1d8f10e828d9f55f68ac00" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", "syn 2.0.24", ] [[package]] name = "tokio" version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "socket2", "tokio-macros", "windows-sys", ] [[package]] name = "tokio-macros" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", "syn 2.0.24", ] [[package]] name = "unicode-ident" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "value-bag" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" [[package]] name = "waker-fn" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[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.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.24", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", "syn 2.0.24", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" netlink-proto-0.11.2/Cargo.toml0000644000000035210000000000100117210ustar # 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-proto" version = "0.11.2" authors = ["Corentin Henry "] description = "async netlink protocol" homepage = "https://github.com/rust-netlink/netlink-proto" readme = "README.md" keywords = [ "netlink", "linux", "async", ] license = "MIT" repository = "https://github.com/rust-netlink/netlink-proto" [[example]] name = "dump_links" [[example]] name = "dump_links_async" required-features = ["smol_socket"] [[example]] name = "audit_netlink_events" [dependencies.bytes] version = "1.0" [dependencies.futures] version = "0.3" [dependencies.log] version = "0.4.8" [dependencies.netlink-packet-core] version = "0.7.0" [dependencies.netlink-sys] version = "0.8.4" default-features = false [dependencies.thiserror] version = "1.0.30" [dependencies.tokio] version = "1.0" features = [ "io-util", "time", ] default-features = false [dev-dependencies.async-std] version = "1.9.0" features = ["attributes"] [dev-dependencies.env_logger] version = "0.8.2" [dev-dependencies.netlink-packet-audit] version = "0.5.0" [dev-dependencies.netlink-packet-route] version = "0.14.1" [dev-dependencies.tokio] version = "1.0.1" features = [ "macros", "rt-multi-thread", ] default-features = false [features] default = ["tokio_socket"] smol_socket = ["netlink-sys/smol_socket"] tokio_socket = ["netlink-sys/tokio_socket"] netlink-proto-0.11.2/Cargo.toml.orig0000644000000022410000000000100126560ustar [package] authors = ["Corentin Henry "] name = "netlink-proto" version = "0.11.2" edition = "2018" homepage = "https://github.com/rust-netlink/netlink-proto" keywords = ["netlink", "linux", "async"] license = "MIT" readme = "README.md" repository = "https://github.com/rust-netlink/netlink-proto" description = "async netlink protocol" [dependencies] bytes = "1.0" log = "0.4.8" futures = "0.3" tokio = { version = "1.0", default-features = false, features = ["io-util","time"] } netlink-packet-core = "0.7.0" netlink-sys = { default-features = false, version = "0.8.4" } thiserror = "1.0.30" [features] default = ["tokio_socket"] tokio_socket = ["netlink-sys/tokio_socket"] smol_socket = ["netlink-sys/smol_socket"] [dev-dependencies] env_logger = "0.8.2" tokio = { version = "1.0.1", default-features = false, features = ["macros", "rt-multi-thread"] } netlink-packet-route = { version = "0.14.1" } netlink-packet-audit = { version = "0.5.0" } async-std = {version = "1.9.0", features = ["attributes"]} [[example]] name = "dump_links" [[example]] name = "dump_links_async" required-features = ["smol_socket"] [[example]] name = "audit_netlink_events" netlink-proto-0.11.2/Cargo.toml.orig000064400000000000000000000022411046102023000154000ustar 00000000000000[package] authors = ["Corentin Henry "] name = "netlink-proto" version = "0.11.2" edition = "2018" homepage = "https://github.com/rust-netlink/netlink-proto" keywords = ["netlink", "linux", "async"] license = "MIT" readme = "README.md" repository = "https://github.com/rust-netlink/netlink-proto" description = "async netlink protocol" [dependencies] bytes = "1.0" log = "0.4.8" futures = "0.3" tokio = { version = "1.0", default-features = false, features = ["io-util","time"] } netlink-packet-core = "0.7.0" netlink-sys = { default-features = false, version = "0.8.4" } thiserror = "1.0.30" [features] default = ["tokio_socket"] tokio_socket = ["netlink-sys/tokio_socket"] smol_socket = ["netlink-sys/smol_socket"] [dev-dependencies] env_logger = "0.8.2" tokio = { version = "1.0.1", default-features = false, features = ["macros", "rt-multi-thread"] } netlink-packet-route = { version = "0.14.1" } netlink-packet-audit = { version = "0.5.0" } async-std = {version = "1.9.0", features = ["attributes"]} [[example]] name = "dump_links" [[example]] name = "dump_links_async" required-features = ["smol_socket"] [[example]] name = "audit_netlink_events" netlink-proto-0.11.2/LICENSE-MIT000064400000000000000000000027731046102023000141570ustar 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-proto-0.11.2/README.md000064400000000000000000000006141046102023000137720ustar 00000000000000# Rust async netlink protocol The `netlink-proto` crate is an asynchronous implementation of the netlink protocol. It only depends on [`netlink-packet-core`][netlink_core_url] for the `NetlinkMessage` type and [`netlink-sys`][netlink_sys_url] for the socket. [netlink_core_url]: https://github.com/rust-netlink/netlink-packet-core [netlink_sys_url]: https://github.com/rust-netlink/netlink-sys netlink-proto-0.11.2/src/codecs.rs000064400000000000000000000107671046102023000151220ustar 00000000000000// SPDX-License-Identifier: MIT use std::{fmt::Debug, io}; use bytes::{BufMut, BytesMut}; use netlink_packet_core::{ NetlinkBuffer, NetlinkDeserializable, NetlinkMessage, NetlinkSerializable, }; /// Protocol to serialize and deserialize messages to and from datagrams /// /// This is separate from `tokio_util::codec::{Decoder, Encoder}` as the /// implementations rely on the buffer containing full datagrams; they won't /// work well with simple bytestreams. /// /// Officially there should be exactly one implementation of this, but the audit /// subsystem ignores way too many rules of the protocol, so they need a /// separate implementation. /// /// Although one could make a tighter binding between `NetlinkMessageCodec` and /// the message types (NetlinkDeserializable+NetlinkSerializable) it can handle, /// this would put quite some overhead on subsystems that followed the spec - so /// we simply default to the proper implementation (in `Connection`) and the /// `audit` code needs to overwrite it. pub trait NetlinkMessageCodec { /// Decode message of given type from datagram payload /// /// There might be more than one message; this needs to be called until it /// either returns `Ok(None)` or an error. fn decode(src: &mut BytesMut) -> io::Result>> where T: NetlinkDeserializable + Debug; /// Encode message to (datagram) buffer fn encode(msg: NetlinkMessage, buf: &mut BytesMut) -> io::Result<()> where T: NetlinkSerializable + Debug; } /// Standard implementation of `NetlinkMessageCodec` pub struct NetlinkCodec { // we don't need an instance of this, just the type _private: (), } impl NetlinkMessageCodec for NetlinkCodec { fn decode(src: &mut BytesMut) -> io::Result>> where T: NetlinkDeserializable + Debug, { debug!("NetlinkCodec: decoding next message"); loop { // If there's nothing to read, return Ok(None) if src.is_empty() { trace!("buffer is empty"); return Ok(None); } // This is a bit hacky because we don't want to keep `src` // borrowed, since we need to mutate it later. let len = match NetlinkBuffer::new_checked(src.as_ref()) { Ok(buf) => buf.length() as usize, Err(e) => { // We either received a truncated packet, or the // packet if malformed (invalid length field). In // both case, we can't decode the datagram, and we // cannot find the start of the next one (if // any). The only solution is to clear the buffer // and potentially lose some datagrams. error!( "failed to decode datagram, clearing buffer: {:?}: {:#x?}.", e, src.as_ref() ); src.clear(); return Ok(None); } }; let bytes = src.split_to(len); let parsed = NetlinkMessage::::deserialize(&bytes); match parsed { Ok(packet) => { trace!("<<< {:?}", packet); return Ok(Some(packet)); } Err(e) => { error!("failed to decode packet {:#x?}: {}", &bytes, e); // continue looping, there may be more datagrams in the // buffer } } } } fn encode(msg: NetlinkMessage, buf: &mut BytesMut) -> io::Result<()> where T: Debug + NetlinkSerializable, { let msg_len = msg.buffer_len(); if buf.remaining_mut() < msg_len { // BytesMut can expand till usize::MAX... unlikely to hit this one. return Err(io::Error::new( io::ErrorKind::Other, format!( "message is {} bytes, but only {} bytes left in the buffer", msg_len, buf.remaining_mut() ), )); } // As NetlinkMessage::serialize needs an initialized buffer anyway // no need for any `unsafe` magic. let old_len = buf.len(); let new_len = old_len + msg_len; buf.resize(new_len, 0); msg.serialize(&mut buf[old_len..][..msg_len]); trace!(">>> {:?}", msg); Ok(()) } } netlink-proto-0.11.2/src/connection.rs000064400000000000000000000257621046102023000160220ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ fmt::Debug, io, pin::Pin, task::{Context, Poll}, }; use futures::{ channel::mpsc::{UnboundedReceiver, UnboundedSender}, Future, Sink, Stream, }; use log::{error, warn}; use netlink_packet_core::{ NetlinkDeserializable, NetlinkMessage, NetlinkPayload, NetlinkSerializable, }; use crate::{ codecs::{NetlinkCodec, NetlinkMessageCodec}, framed::NetlinkFramed, sys::{AsyncSocket, SocketAddr}, Protocol, Request, Response, }; #[cfg(feature = "tokio_socket")] use netlink_sys::TokioSocket as DefaultSocket; #[cfg(not(feature = "tokio_socket"))] type DefaultSocket = (); /// Connection to a Netlink socket, running in the background. /// /// [`ConnectionHandle`](struct.ConnectionHandle.html) are used to pass new /// requests to the `Connection`, that in turn, sends them through the netlink /// socket. pub struct Connection where T: Debug + NetlinkSerializable + NetlinkDeserializable, { socket: NetlinkFramed, protocol: Protocol>>, /// Channel used by the user to pass requests to the connection. requests_rx: Option>>, /// Channel used to transmit to the ConnectionHandle the unsolicited /// messages received from the socket (multicast messages for instance). unsolicited_messages_tx: Option, SocketAddr)>>, socket_closed: bool, } impl Connection where T: Debug + NetlinkSerializable + NetlinkDeserializable + Unpin, S: AsyncSocket, C: NetlinkMessageCodec, { pub(crate) fn new( requests_rx: UnboundedReceiver>, unsolicited_messages_tx: UnboundedSender<( NetlinkMessage, SocketAddr, )>, protocol: isize, ) -> io::Result { let socket = S::new(protocol)?; Ok(Connection { socket: NetlinkFramed::new(socket), protocol: Protocol::new(), requests_rx: Some(requests_rx), unsolicited_messages_tx: Some(unsolicited_messages_tx), socket_closed: false, }) } pub fn socket_mut(&mut self) -> &mut S { self.socket.get_mut() } pub fn poll_send_messages(&mut self, cx: &mut Context) { trace!("poll_send_messages called"); let Connection { ref mut socket, ref mut protocol, .. } = self; let mut socket = Pin::new(socket); while !protocol.outgoing_messages.is_empty() { trace!( "found outgoing message to send checking if socket is ready" ); if let Poll::Ready(Err(e)) = Pin::as_mut(&mut socket).poll_ready(cx) { // Sink errors are usually not recoverable. The socket // probably shut down. warn!("netlink socket shut down: {:?}", e); self.socket_closed = true; return; } let (mut message, addr) = protocol.outgoing_messages.pop_front().unwrap(); message.finalize(); trace!("sending outgoing message"); if let Err(e) = Pin::as_mut(&mut socket).start_send((message, addr)) { error!("failed to send message: {:?}", e); self.socket_closed = true; return; } } trace!("poll_send_messages done"); self.poll_flush(cx) } pub fn poll_flush(&mut self, cx: &mut Context) { trace!("poll_flush called"); if let Poll::Ready(Err(e)) = Pin::new(&mut self.socket).poll_flush(cx) { warn!("error flushing netlink socket: {:?}", e); self.socket_closed = true; } } pub fn poll_read_messages(&mut self, cx: &mut Context) { trace!("poll_read_messages called"); let mut socket = Pin::new(&mut self.socket); loop { trace!("polling socket"); match socket.as_mut().poll_next(cx) { Poll::Ready(Some((message, addr))) => { trace!("read datagram from socket"); self.protocol.handle_message(message, addr); } Poll::Ready(None) => { warn!("netlink socket stream shut down"); self.socket_closed = true; return; } Poll::Pending => { trace!("no datagram read from socket"); return; } } } } pub fn poll_requests(&mut self, cx: &mut Context) { trace!("poll_requests called"); if let Some(mut stream) = self.requests_rx.as_mut() { loop { match Pin::new(&mut stream).poll_next(cx) { Poll::Ready(Some(request)) => { self.protocol.request(request) } Poll::Ready(None) => break, Poll::Pending => return, } } let _ = self.requests_rx.take(); trace!("no new requests to handle poll_requests done"); } } pub fn forward_unsolicited_messages(&mut self) { if self.unsolicited_messages_tx.is_none() { while let Some((message, source)) = self.protocol.incoming_requests.pop_front() { warn!( "ignoring unsolicited message {:?} from {:?}", message, source ); } return; } trace!("forward_unsolicited_messages called"); let mut ready = false; let Connection { ref mut protocol, ref mut unsolicited_messages_tx, .. } = self; while let Some((message, source)) = protocol.incoming_requests.pop_front() { if unsolicited_messages_tx .as_mut() .unwrap() .unbounded_send((message, source)) .is_err() { // The channel is unbounded so the only error that can // occur is that the channel is closed because the // receiver was dropped warn!("failed to forward message to connection handle: channel closed"); ready = true; break; } } if ready || self .unsolicited_messages_tx .as_ref() .map_or(true, |x| x.is_closed()) { // The channel is closed so we can drop the sender. let _ = self.unsolicited_messages_tx.take(); // purge `protocol.incoming_requests` self.forward_unsolicited_messages(); } trace!("forward_unsolicited_messages done"); } pub fn forward_responses(&mut self) { trace!("forward_responses called"); let protocol = &mut self.protocol; while let Some(response) = protocol.incoming_responses.pop_front() { let Response { message, done, metadata: tx, } = response; if done { use NetlinkPayload::*; match &message.payload { // Since `self.protocol` set the `done` flag here, // we know it has already dropped the request and // its associated metadata, ie the UnboundedSender // used to forward messages back to the // ConnectionHandle. By just continuing we're // dropping the last instance of that sender, // hence closing the channel and signaling the // handle that no more messages are expected. Noop | Done(_) => { trace!( "not forwarding Noop/Ack/Done message to \ the handle" ); continue; } // I'm not sure how we should handle overrun messages Overrun(_) => unimplemented!("overrun is not handled yet"), // We need to forward error messages and messages // that are part of the netlink subprotocol, // because only the user knows how they want to // handle them. Error(err_msg) => { if err_msg.code.is_none() { trace!( "not forwarding Noop/Ack/Done message to \ the handle" ); continue; } } InnerMessage(_) => {} _ => {} } } trace!("forwarding response to the handle"); if tx.unbounded_send(message).is_err() { // With an unboundedsender, an error can // only happen if the receiver is closed. warn!("failed to forward response back to the handle"); } } trace!("forward_responses done"); } pub fn should_shut_down(&self) -> bool { self.socket_closed || (self.unsolicited_messages_tx.is_none() && self.requests_rx.is_none()) } } impl Future for Connection where T: Debug + NetlinkSerializable + NetlinkDeserializable + Unpin, S: AsyncSocket, C: NetlinkMessageCodec, { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { trace!("polling Connection"); let pinned = self.get_mut(); debug!("reading incoming messages"); pinned.poll_read_messages(cx); debug!("forwarding unsolicited messages to the connection handle"); pinned.forward_unsolicited_messages(); debug!( "forwaring responses to previous requests to the connection handle" ); pinned.forward_responses(); debug!("handling requests"); pinned.poll_requests(cx); debug!("sending messages"); pinned.poll_send_messages(cx); trace!("done polling Connection"); if pinned.should_shut_down() { Poll::Ready(()) } else { Poll::Pending } } } #[cfg(all(test, feature = "tokio_socket"))] mod tests { use crate::new_connection; use crate::sys::protocols::NETLINK_AUDIT; use netlink_packet_audit::AuditMessage; use tokio::time; #[tokio::test] async fn connection_is_closed() { let (conn, _, _) = new_connection::(NETLINK_AUDIT).unwrap(); let join_handle = tokio::spawn(conn); time::sleep(time::Duration::from_millis(200)).await; assert!(join_handle.is_finished()); } } netlink-proto-0.11.2/src/errors.rs000064400000000000000000000011121046102023000151560ustar 00000000000000// SPDX-License-Identifier: MIT use std::io; use netlink_packet_core::NetlinkMessage; #[derive(thiserror::Error, Debug)] pub enum Error { /// The netlink connection is closed #[error("the netlink connection is closed")] ConnectionClosed, /// Received an error message as a response #[error("received an error message as a response: {0:?}")] NetlinkError(NetlinkMessage), /// Error while reading from or writing to the netlink socket #[error("error while reading from or writing to the netlink socket: {0}")] SocketIo(#[from] io::Error), } netlink-proto-0.11.2/src/framed.rs000064400000000000000000000133141046102023000151070ustar 00000000000000// SPDX-License-Identifier: MIT use bytes::BytesMut; use std::{ fmt::Debug, io, marker::PhantomData, pin::Pin, task::{Context, Poll}, }; use futures::{Sink, Stream}; use log::error; use crate::{ codecs::NetlinkMessageCodec, sys::{AsyncSocket, SocketAddr}, }; use netlink_packet_core::{ NetlinkDeserializable, NetlinkMessage, NetlinkSerializable, }; pub struct NetlinkFramed { socket: S, // see https://doc.rust-lang.org/nomicon/phantom-data.html // "invariant" seems like the safe choice; using `fn(T) -> T` // should make it invariant but still Send+Sync. msg_type: PhantomData T>, // invariant codec: PhantomData C>, // invariant reader: BytesMut, writer: BytesMut, in_addr: SocketAddr, out_addr: SocketAddr, flushed: bool, } impl Stream for NetlinkFramed where T: NetlinkDeserializable + Debug, S: AsyncSocket, C: NetlinkMessageCodec, { type Item = (NetlinkMessage, SocketAddr); fn poll_next( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { let Self { ref mut socket, ref mut in_addr, ref mut reader, .. } = Pin::get_mut(self); loop { match C::decode::(reader) { Ok(Some(item)) => return Poll::Ready(Some((item, *in_addr))), Ok(None) => {} Err(e) => { error!("unrecoverable error in decoder: {:?}", e); return Poll::Ready(None); } } reader.clear(); reader.reserve(INITIAL_READER_CAPACITY); *in_addr = match ready!(socket.poll_recv_from(cx, reader)) { Ok(addr) => addr, Err(e) => { error!("failed to read from netlink socket: {:?}", e); return Poll::Ready(None); } }; } } } impl Sink<(NetlinkMessage, SocketAddr)> for NetlinkFramed where T: NetlinkSerializable + Debug, S: AsyncSocket, C: NetlinkMessageCodec, { type Error = io::Error; fn poll_ready( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { if !self.flushed { match self.poll_flush(cx)? { Poll::Ready(()) => {} Poll::Pending => return Poll::Pending, } } Poll::Ready(Ok(())) } fn start_send( self: Pin<&mut Self>, item: (NetlinkMessage, SocketAddr), ) -> Result<(), Self::Error> { trace!("sending frame"); let (frame, out_addr) = item; let pin = self.get_mut(); C::encode(frame, &mut pin.writer)?; pin.out_addr = out_addr; pin.flushed = false; trace!("frame encoded; length={}", pin.writer.len()); Ok(()) } fn poll_flush( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { if self.flushed { return Poll::Ready(Ok(())); } trace!("flushing frame; length={}", self.writer.len()); let Self { ref mut socket, ref mut out_addr, ref mut writer, .. } = *self; let n = ready!(socket.poll_send_to(cx, writer, out_addr))?; trace!("written {}", n); let wrote_all = n == self.writer.len(); self.writer.clear(); self.flushed = true; let res = if wrote_all { Ok(()) } else { Err(io::Error::new( io::ErrorKind::Other, "failed to write entire datagram to socket", )) }; Poll::Ready(res) } fn poll_close( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { ready!(self.poll_flush(cx))?; Poll::Ready(Ok(())) } } // The theoritical max netlink packet size is 32KB for a netlink // message since Linux 4.9 (16KB before). See: // https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=d35c99ff77ecb2eb239731b799386f3b3637a31e const INITIAL_READER_CAPACITY: usize = 64 * 1024; const INITIAL_WRITER_CAPACITY: usize = 8 * 1024; impl NetlinkFramed { /// Create a new `NetlinkFramed` backed by the given socket and codec. /// /// See struct level documentation for more details. pub fn new(socket: S) -> Self { Self { socket, msg_type: PhantomData, codec: PhantomData, out_addr: SocketAddr::new(0, 0), in_addr: SocketAddr::new(0, 0), reader: BytesMut::with_capacity(INITIAL_READER_CAPACITY), writer: BytesMut::with_capacity(INITIAL_WRITER_CAPACITY), flushed: true, } } /// Returns a reference to the underlying I/O stream wrapped by `Framed`. /// /// # Note /// /// Care should be taken to not tamper with the underlying stream of data /// coming in as it may corrupt the stream of frames otherwise being worked /// with. pub fn get_ref(&self) -> &S { &self.socket } /// Returns a mutable reference to the underlying I/O stream wrapped by /// `Framed`. /// /// # Note /// /// Care should be taken to not tamper with the underlying stream of data /// coming in as it may corrupt the stream of frames otherwise being worked /// with. pub fn get_mut(&mut self) -> &mut S { &mut self.socket } /// Consumes the `Framed`, returning its underlying I/O stream. pub fn into_inner(self) -> S { self.socket } } netlink-proto-0.11.2/src/handle.rs000064400000000000000000000044771046102023000151160ustar 00000000000000// SPDX-License-Identifier: MIT use futures::{ channel::mpsc::{unbounded, UnboundedSender}, Stream, }; use netlink_packet_core::NetlinkMessage; use std::fmt::Debug; use crate::{errors::Error, sys::SocketAddr, Request}; /// A handle to pass requests to a [`Connection`](struct.Connection.html). #[derive(Clone, Debug)] pub struct ConnectionHandle where T: Debug, { requests_tx: UnboundedSender>, } impl ConnectionHandle where T: Debug, { pub(crate) fn new(requests_tx: UnboundedSender>) -> Self { ConnectionHandle { requests_tx } } /// Send a new request and get the response as a stream of messages. Note /// that some messages are not part of the response stream: /// /// - **acknowledgements**: when an acknowledgement is received, the stream /// is closed /// - **end of dump messages**: similarly, upon receiving an "end of dump" /// message, the stream is /// closed pub fn request( &mut self, message: NetlinkMessage, destination: SocketAddr, ) -> Result>, Error> { let (tx, rx) = unbounded::>(); let request = Request::from((message, destination, tx)); debug!("handle: forwarding new request to connection"); UnboundedSender::unbounded_send(&self.requests_tx, request).map_err( |e| { // the channel is unbounded, so it can't be full. If this // failed, it means the Connection shut down. if e.is_full() { panic!("internal error: unbounded channel full?!"); } else if e.is_disconnected() { Error::ConnectionClosed } else { panic!("unknown error: {:?}", e); } }, )?; Ok(rx) } pub fn notify( &mut self, message: NetlinkMessage, destination: SocketAddr, ) -> Result<(), Error> { let (tx, _rx) = unbounded::>(); let request = Request::from((message, destination, tx)); debug!("handle: forwarding new request to connection"); UnboundedSender::unbounded_send(&self.requests_tx, request) .map_err(|_| Error::ConnectionClosed) } } netlink-proto-0.11.2/src/lib.rs000064400000000000000000000221501046102023000144150ustar 00000000000000// SPDX-License-Identifier: MIT //! `netlink-proto` is an asynchronous implementation of the Netlink //! protocol. //! //! # Example: listening for audit events //! //! This example shows how to use `netlink-proto` with the `tokio` //! runtime to print audit events. It requires extra external //! dependencies: //! //! - `futures = "^0.3"` //! - `tokio = "^1.0"` //! - `netlink-packet-audit = "^0.1"` //! //! ```rust,no_run //! use futures::stream::StreamExt; //! use netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_ACK, //! NLM_F_REQUEST}; //! use netlink_packet_audit::{ //! AuditMessage, //! StatusMessage, //! }; //! use std::process; //! //! use netlink_proto::{ //! new_connection, //! sys::{protocols::NETLINK_AUDIT, SocketAddr}, //! }; //! //! const AUDIT_STATUS_ENABLED: u32 = 1; //! const AUDIT_STATUS_PID: u32 = 4; //! //! #[tokio::main] //! async fn main() -> Result<(), String> { //! // Create a netlink socket. Here: //! // //! // - `conn` is a `Connection` that has the netlink socket. It's a //! // `Future` that keeps polling the socket and must be spawned an //! // the event loop. //! // //! // - `handle` is a `Handle` to the `Connection`. We use it to send //! // netlink messages and receive responses to these messages. //! // //! // - `messages` is a channel receiver through which we receive //! // messages that we have not solicited, ie that are not //! // response to a request we made. In this example, we'll receive //! // the audit event through that channel. //! let (conn, mut handle, mut messages) = new_connection(NETLINK_AUDIT) //! .map_err(|e| format!("Failed to create a new netlink connection: {}", e))?; //! //! // Spawn the `Connection` so that it starts polling the netlink //! // socket in the background. //! tokio::spawn(conn); //! //! // Use the `ConnectionHandle` to send a request to the kernel //! // asking it to start multicasting audit event messages. //! tokio::spawn(async move { //! // Craft the packet to enable audit events //! 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; //! //! // We'll send unicast messages to the kernel. //! let kernel_unicast: SocketAddr = SocketAddr::new(0, 0); //! let mut response = match handle.request(nl_msg, kernel_unicast) { //! Ok(response) => response, //! Err(e) => { //! eprintln!("{}", e); //! return; //! } //! }; //! //! while let Some(message) = response.next().await { //! if let NetlinkPayload::Error(err_message) = message.payload { //! eprintln!("Received an error message: {:?}", err_message); //! return; //! } //! } //! }); //! //! // Finally, start receiving event through the `messages` channel. //! println!("Starting to print audit events... press ^C to interrupt"); //! while let Some((message, _addr)) = messages.next().await { //! if let NetlinkPayload::Error(err_message) = message.payload { //! eprintln!("received an error message: {:?}", err_message); //! } else { //! println!("{:?}", message); //! } //! } //! //! Ok(()) //! } //! ``` //! //! # Example: dumping all the machine's links //! //! This example shows how to use `netlink-proto` with the ROUTE //! protocol. //! //! Here we do not use `netlink_proto::new_connection()`, and instead //! create the socket manually and use call `send()` and `receive()` //! directly. In the previous example, the `NetlinkFramed` was wrapped //! in a `Connection` which was polled automatically by the runtime. //! //! ```rust,no_run //! use futures::StreamExt; //! //! use netlink_packet_route::{ //! LinkMessage, //! NetlinkHeader, //! NetlinkMessage, //! RtnlMessage, //! NLM_F_DUMP, //! NLM_F_REQUEST, //! }; //! //! use netlink_proto::{ //! new_connection, //! sys::{protocols::NETLINK_ROUTE, SocketAddr}, //! }; //! //! #[tokio::main] //! async fn main() -> Result<(), String> { //! // Create the netlink socket. Here, we won't use the channel that //! // receives unsolicited messages. //! let (conn, mut handle, _) = new_connection(NETLINK_ROUTE) //! .map_err(|e| format!("Failed to create a new netlink connection: {}", e))?; //! //! // Spawn the `Connection` in the background //! tokio::spawn(conn); //! //! // Create the netlink message that requests the links to be dumped //! let mut nl_hdr = NetlinkHeader::default(); //! nl_hdr.flags = NLM_F_DUMP | NLM_F_REQUEST; //! //! let msg = NetlinkMessage::new( //! nl_hdr, //! RtnlMessage::GetLink(LinkMessage::default()).into(), //! ); //! //! // Send the request //! let mut response = handle //! .request(msg, SocketAddr::new(0, 0)) //! .map_err(|e| format!("Failed to send request: {}", e))?; //! //! // Print all the messages received in response //! loop { //! if let Some(packet) = response.next().await { //! println!("<<< {:?}", packet); //! } else { //! break; //! } //! } //! //! Ok(()) //! } //! ``` #[macro_use] extern crate futures; #[macro_use] extern crate log; mod codecs; pub use crate::codecs::*; mod framed; pub use crate::framed::*; mod protocol; pub(crate) use self::protocol::{Protocol, Response}; pub(crate) type Request = self::protocol::Request< T, UnboundedSender>, >; mod connection; pub use crate::connection::*; mod errors; pub use crate::errors::*; mod handle; pub use crate::handle::*; use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use std::{fmt::Debug, io}; pub(crate) use netlink_packet_core as packet; pub mod sys { pub use netlink_sys::{protocols, AsyncSocket, AsyncSocketExt, SocketAddr}; #[cfg(feature = "tokio_socket")] pub use netlink_sys::TokioSocket; #[cfg(feature = "smol_socket")] pub use netlink_sys::SmolSocket; } /// Create a new Netlink connection for the given Netlink protocol, and returns /// a handle to that connection as well as a stream of unsolicited messages /// received by that connection (unsolicited here means messages that are not a /// response to a request made by the `Connection`). `Connection` wraps a /// Netlink socket and implements the Netlink protocol. /// /// `protocol` must be one of the [`crate::sys::protocols`][protos] constants. /// /// `T` is the type of netlink messages used for this protocol. For instance, if /// you're using the `NETLINK_AUDIT` protocol with the `netlink-packet-audit` /// crate, `T` will be `netlink_packet_audit::AuditMessage`. More generally, `T` /// is anything that can be serialized and deserialized into a Netlink message. /// See the `netlink_packet_core` documentation for details about the /// `NetlinkSerializable` and `NetlinkDeserializable` traits. /// /// Most of the time, users will want to spawn the `Connection` on an async /// runtime, and use the handle to send messages. /// /// [protos]: crate::sys::protocols #[cfg(feature = "tokio_socket")] #[allow(clippy::type_complexity)] pub fn new_connection( protocol: isize, ) -> io::Result<( Connection, ConnectionHandle, UnboundedReceiver<(packet::NetlinkMessage, sys::SocketAddr)>, )> where T: Debug + packet::NetlinkSerializable + packet::NetlinkDeserializable + Unpin, { new_connection_with_codec(protocol) } /// Variant of [`new_connection`] that allows specifying a socket type to use /// for async handling #[allow(clippy::type_complexity)] pub fn new_connection_with_socket( protocol: isize, ) -> io::Result<( Connection, ConnectionHandle, UnboundedReceiver<(packet::NetlinkMessage, sys::SocketAddr)>, )> where T: Debug + packet::NetlinkSerializable + packet::NetlinkDeserializable + Unpin, S: sys::AsyncSocket, { new_connection_with_codec(protocol) } /// Variant of [`new_connection`] that allows specifying a socket type to use /// for async handling and a special codec #[allow(clippy::type_complexity)] pub fn new_connection_with_codec( protocol: isize, ) -> io::Result<( Connection, ConnectionHandle, UnboundedReceiver<(packet::NetlinkMessage, sys::SocketAddr)>, )> where T: Debug + packet::NetlinkSerializable + packet::NetlinkDeserializable + Unpin, S: sys::AsyncSocket, C: NetlinkMessageCodec, { let (requests_tx, requests_rx) = unbounded::>(); let (messages_tx, messages_rx) = unbounded::<(packet::NetlinkMessage, sys::SocketAddr)>(); Ok(( Connection::new(requests_rx, messages_tx, protocol)?, ConnectionHandle::new(requests_tx), messages_rx, )) } netlink-proto-0.11.2/src/protocol/mod.rs000064400000000000000000000002601046102023000162650ustar 00000000000000// SPDX-License-Identifier: MIT #[allow(clippy::module_inception)] mod protocol; mod request; pub(crate) use protocol::{Protocol, Response}; pub(crate) use request::Request; netlink-proto-0.11.2/src/protocol/protocol.rs000064400000000000000000000121701046102023000173520ustar 00000000000000// SPDX-License-Identifier: MIT use std::{ collections::{hash_map, HashMap, VecDeque}, fmt::Debug, }; use netlink_packet_core::{ constants::*, NetlinkDeserializable, NetlinkMessage, NetlinkPayload, NetlinkSerializable, }; use super::Request; use crate::sys::SocketAddr; #[derive(Debug, Eq, PartialEq, Hash)] struct RequestId { sequence_number: u32, port: u32, } impl RequestId { fn new(sequence_number: u32, port: u32) -> Self { Self { sequence_number, port, } } } #[derive(Debug, Eq, PartialEq)] pub(crate) struct Response { pub done: bool, pub message: NetlinkMessage, pub metadata: M, } #[derive(Debug)] struct PendingRequest { expecting_ack: bool, metadata: M, } #[derive(Debug, Default)] pub(crate) struct Protocol { /// Counter that is incremented for each message sent sequence_id: u32, /// Requests for which we're awaiting a response. Metadata are /// associated with each request. pending_requests: HashMap>, /// Responses to pending requests pub incoming_responses: VecDeque>, /// Requests from remote peers pub incoming_requests: VecDeque<(NetlinkMessage, SocketAddr)>, /// The messages to be sent out pub outgoing_messages: VecDeque<(NetlinkMessage, SocketAddr)>, } impl Protocol where T: Debug + NetlinkSerializable + NetlinkDeserializable, M: Debug + Clone, { pub fn new() -> Self { Self { sequence_id: 0, pending_requests: HashMap::new(), incoming_responses: VecDeque::new(), incoming_requests: VecDeque::new(), outgoing_messages: VecDeque::new(), } } pub fn handle_message( &mut self, message: NetlinkMessage, source: SocketAddr, ) { let request_id = RequestId::new( message.header.sequence_number, source.port_number(), ); debug!("handling messages (request id = {:?})", request_id); if let hash_map::Entry::Occupied(entry) = self.pending_requests.entry(request_id) { Self::handle_response(&mut self.incoming_responses, entry, message); } else { self.incoming_requests.push_back((message, source)); } } fn handle_response( incoming_responses: &mut VecDeque>, entry: hash_map::OccupiedEntry>, message: NetlinkMessage, ) { let entry_key; let mut request_id = entry.key(); debug!("handling response to request {:?}", request_id); // A request is processed if we receive an Ack, Error, // Done, Overrun, or InnerMessage without the // multipart flag and we were not expecting an Ack let done = match message.payload { NetlinkPayload::InnerMessage(_) if message.header.flags & NLM_F_MULTIPART == NLM_F_MULTIPART => { false } NetlinkPayload::InnerMessage(_) => !entry.get().expecting_ack, _ => true, }; let metadata = if done { trace!("request {:?} fully processed", request_id); let (k, v) = entry.remove_entry(); entry_key = k; request_id = &entry_key; v.metadata } else { trace!("more responses to request {:?} may come", request_id); entry.get().metadata.clone() }; let response = Response:: { done, message, metadata, }; incoming_responses.push_back(response); debug!("done handling response to request {:?}", request_id); } pub fn request(&mut self, request: Request) { let Request { mut message, metadata, destination, } = request; self.set_sequence_id(&mut message); let request_id = RequestId::new(self.sequence_id, destination.port_number()); let flags = message.header.flags; self.outgoing_messages.push_back((message, destination)); // If we expect a response, we store the request id so that we // can map the response to this specific request. // // Note that we expect responses in three cases only: // - when the request has the NLM_F_REQUEST flag // - when the request has the NLM_F_ACK flag // - when the request has the NLM_F_ECHO flag let expecting_ack = flags & NLM_F_ACK == NLM_F_ACK; if flags & NLM_F_REQUEST == NLM_F_REQUEST || flags & NLM_F_ECHO == NLM_F_ECHO || expecting_ack { self.pending_requests.insert( request_id, PendingRequest { expecting_ack, metadata, }, ); } } fn set_sequence_id(&mut self, message: &mut NetlinkMessage) { self.sequence_id += 1; message.header.sequence_number = self.sequence_id; } } netlink-proto-0.11.2/src/protocol/request.rs000064400000000000000000000014541046102023000172040ustar 00000000000000// SPDX-License-Identifier: MIT use std::fmt::Debug; use netlink_packet_core::NetlinkMessage; use crate::sys::SocketAddr; #[derive(Debug)] pub(crate) struct Request { pub metadata: M, pub message: NetlinkMessage, pub destination: SocketAddr, } impl From<(NetlinkMessage, SocketAddr, M)> for Request where T: Debug, M: Debug, { fn from(parts: (NetlinkMessage, SocketAddr, M)) -> Self { Request { message: parts.0, destination: parts.1, metadata: parts.2, } } } impl From> for (NetlinkMessage, SocketAddr, M) where T: Debug, M: Debug, { fn from(req: Request) -> (NetlinkMessage, SocketAddr, M) { (req.message, req.destination, req.metadata) } }