Merge pull request #7 from EFForg/fix-1

Drive log reading locally
This commit is contained in:
Cooper Quintin
2023-12-13 16:09:32 -08:00
committed by GitHub
8 changed files with 1582 additions and 193 deletions

View File

@@ -2,5 +2,8 @@
target = "armv7-unknown-linux-gnueabihf"
rustflags = ["-C", "target-feature=+crt-static"]
[alias]
test_pc = "test --target=x86_64-unknown-linux-gnu"
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

710
Cargo.lock generated
View File

@@ -2,27 +2,394 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder_slice"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b294e30387378958e8bf8f4242131b930ea615ff81e8cac2440cea0a6013190"
dependencies = [
"byteorder",
]
[[package]]
name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.48.5",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "crc"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
dependencies = [
"crc-catalog",
]
[[package]]
name = "crc-catalog"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]]
name = "darling"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
dependencies = [
"darling_core",
"quote",
"syn 1.0.109",
]
[[package]]
name = "deku"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819b87cc7a05b3abe3fc38e59b3980a5fd3162f25a247116441a9171d3e84481"
dependencies = [
"bitvec",
"deku_derive",
"log",
]
[[package]]
name = "deku_derive"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e2ca12572239215a352a74ad7c776d7e8a914f8a23511c6cbedddd887e5009e"
dependencies = [
"darling",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive-into-owned"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d94d81e3819a7b06a8638f448bc6339371ca9b6076a99d4a43eece3c4c923"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "diag"
version = "0.1.0"
dependencies = [
"bytes",
"chrono",
"crc",
"deku",
"env_logger",
"libc",
"log",
"pcap-file",
"thiserror",
]
[[package]]
name = "env_logger"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
dependencies = [
"humantime",
"is-terminal",
"log",
"regex",
"termcolor",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "hermit-abi"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "js-sys"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "pcap-file"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc1f139757b058f9f37b76c48501799d12c9aa0aa4c0d4c980b062ee925d1b2"
dependencies = [
"byteorder_slice",
"derive-into-owned",
"thiserror",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
"once_cell",
"toml_edit",
]
[[package]]
name = "proc-macro2"
version = "1.0.69"
@@ -41,6 +408,71 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustix"
version = "0.38.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[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.39"
@@ -52,6 +484,21 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "termcolor"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.50"
@@ -69,7 +516,24 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.39",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
[[package]]
name = "toml_edit"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]]
@@ -77,3 +541,247 @@ name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasm-bindgen"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
[[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.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
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-core"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
dependencies = [
"memchr",
]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]

View File

@@ -7,6 +7,12 @@ edition = "2021"
[dependencies]
bytes = "1.5.0"
chrono = "0.4.31"
crc = "3.0.1"
deku = { version = "0.16.0", features = ["logging"] }
env_logger = "0.10.1"
libc = "0.2.150"
log = "0.4.20"
pcap-file = "2.0.0"
thiserror = "1.0.50"

401
src/diag.rs Normal file
View File

@@ -0,0 +1,401 @@
//! Diag protocol serialization/deserialization
use chrono::{DateTime, FixedOffset};
use deku::prelude::*;
#[derive(Debug, Clone, DekuWrite)]
pub struct RequestContainer {
pub data_type: DataType,
#[deku(skip)]
pub use_mdm: bool,
#[deku(skip, cond = "!*use_mdm")]
pub mdm_field: i32,
pub hdlc_encapsulated_request: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, DekuWrite)]
#[deku(type = "u32")]
pub enum Request {
#[deku(id = "115")]
LogConfig(LogConfigRequest),
}
#[derive(Debug, Clone, PartialEq, DekuWrite)]
#[deku(type = "u32", endian = "little")]
pub enum LogConfigRequest {
#[deku(id = "1")]
RetrieveIdRanges,
#[deku(id = "3")]
SetMask {
log_type: u32,
log_mask_bitsize: u32,
log_mask: Vec<u8>,
}
}
#[derive(Debug, Clone, PartialEq, DekuRead, DekuWrite)]
#[deku(type = "u32", endian = "little")]
pub enum DataType {
#[deku(id = "32")]
UserSpace,
#[deku(id_pat = "_")]
Other(u32),
}
#[derive(Debug, Clone, DekuRead)]
pub struct MessagesContainer {
pub data_type: DataType,
pub num_messages: u32,
#[deku(count = "num_messages")]
pub messages: Vec<HdlcEncapsulatedMessage>,
}
#[derive(Debug, Clone, DekuRead)]
pub struct HdlcEncapsulatedMessage {
pub len: u32,
#[deku(count = "len")]
pub data: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, DekuRead)]
#[deku(type = "u8")]
pub enum Message {
#[deku(id = "16")]
Log {
pending_msgs: u8,
outer_length: u16,
inner_length: u16,
log_type: u16,
timestamp: Timestamp,
//#[deku(count = "inner_length - 12")]
#[deku(ctx = "*log_type, *inner_length - 12")]
body: LogBody,
},
// kinda unpleasant deku hackery here. deku expects an enum's variant to be
// right before its data, but in this case, a status value comes between the
// variants and the data. so we need to use deku's context (ctx) feature to
// pass those opcodes down to their respective parsers.
#[deku(id_pat = "_")]
Response {
opcode: u32,
subopcode: u32,
status: u32,
#[deku(ctx = "*opcode, *subopcode")]
payload: ResponsePayload,
},
}
#[derive(Debug, Clone, PartialEq, DekuRead)]
#[deku(ctx = "log_type: u16, hdr_len: u16", id = "log_type")]
pub enum LogBody {
#[deku(id = "0x412f")]
WcdmaSignallingMessage {
channel_type: u8,
radio_bearer: u8,
length: u16,
#[deku(count = "length")]
msg: Vec<u8>,
},
#[deku(id = "0x512f")]
GsmRrSignallingMessage {
channel_type: u8,
message_type: u8,
length: u8,
#[deku(count = "length")]
msg: Vec<u8>,
},
#[deku(id = "0x5226")]
GprsMacSignallingMessage {
channel_type: u8,
message_type: u8,
length: u8,
#[deku(count = "length")]
msg: Vec<u8>,
},
#[deku(id = "0xb0c0")]
LteRrcOtaMessage{
ext_header_version: u8,
#[deku(ctx = "*ext_header_version")]
packet: LteRrcOtaPacket,
},
#[deku(id_pat = "0xb0e2 | 0xb0e3 | 0xb0ec | 0xb0ed")]
Nas4GMessage {
ext_header_version: u8,
rrc_rel: u8,
rrc_version_minor: u8,
rrc_version_major: u8,
#[deku(count = "hdr_len - 4")] // is this right??
msg: Vec<u8>,
},
#[deku(id = "0x11eb")]
IpTraffic {
#[deku(count = "hdr_len - 8")] // is this right???
msg: Vec<u8>,
},
#[deku(id = "0x713a")]
UmtsNasOtaMessage {
is_uplink: u8,
length: u32,
#[deku(count = "length")]
msg: Vec<u8>,
},
#[deku(id = "0xb821")]
NrRrcOtaMessage {
#[deku(count = "hdr_len")]
msg: Vec<u8>,
}
}
#[derive(Debug, Clone, PartialEq, DekuRead)]
#[deku(ctx = "ext_header_version: u8", id = "ext_header_version")]
pub enum LteRrcOtaPacket {
#[deku(id_pat = "0..=4")]
V0 {
rrc_rel_maj: u8,
rrc_rel_min: u8,
bearer_id: u8,
phy_cell_id: u16,
earfcn: u16,
sfn_subfn: u16,
pdu_num: u8,
len: u16,
#[deku(count = "len")]
packet: Vec<u8>,
},
#[deku(id_pat = "5..=7")]
V5 {
rrc_rel_maj: u8,
rrc_rel_min: u8,
bearer_id: u8,
phy_cell_id: u16,
earfcn: u16,
sfn_subfn: u16,
pdu_num: u8,
sib_mask: u32,
len: u16,
#[deku(count = "len")]
packet: Vec<u8>,
},
#[deku(id_pat = "8..=24")]
V8 {
rrc_rel_maj: u8,
rrc_rel_min: u8,
bearer_id: u8,
phy_cell_id: u16,
earfcn: u32,
sfn_subfn: u16,
pdu_num: u8,
sib_mask: u32,
len: u16,
#[deku(count = "len")]
packet: Vec<u8>,
},
#[deku(id_pat = "25..")]
V25 {
rrc_rel_maj: u8,
rrc_rel_min: u8,
nr_rrc_rel_maj: u8,
nr_rrc_rel_min: u8,
bearer_id: u8,
phy_cell_id: u16,
earfcn: u32,
sfn_subfn: u16,
pdu_num: u8,
sib_mask: u32,
len: u16,
#[deku(count = "len")]
packet: Vec<u8>,
},
}
impl LteRrcOtaPacket {
fn get_sfn_subfn(&self) -> u16 {
match self {
LteRrcOtaPacket::V0 { sfn_subfn, .. } => *sfn_subfn,
LteRrcOtaPacket::V5 { sfn_subfn, .. } => *sfn_subfn,
LteRrcOtaPacket::V8 { sfn_subfn, .. } => *sfn_subfn,
LteRrcOtaPacket::V25 { sfn_subfn, .. } => *sfn_subfn,
}
}
pub fn get_sfn(&self) -> u16 {
self.get_sfn_subfn() >> 4
}
pub fn get_subfn(&self) -> u16 {
self.get_sfn_subfn() & 0xf
}
}
#[derive(Debug, Clone, PartialEq, DekuRead)]
#[deku(endian = "little")]
pub struct Timestamp {
pub ts: u64,
}
impl Timestamp {
pub fn to_datetime(&self) -> DateTime<FixedOffset> {
// Upper 48 bits: epoch at 1980-01-06 00:00:00, incremented by 1 for 1/800s
// Lower 16 bits: time since last 1/800s tick in 1/32 chip units
let ts_upper = self.ts >> 16;
let ts_lower = self.ts & 0xffff;
let epoch = chrono::DateTime::parse_from_rfc3339("1980-01-06T00:00:00-00:00").unwrap();
let mut delta_seconds = ts_upper as f64 * 1.25;
delta_seconds += ts_lower as f64 / 40960.0;
let ts_delta = chrono::Duration::milliseconds(delta_seconds as i64);
epoch + ts_delta
}
}
#[derive(Debug, Clone, PartialEq, DekuRead)]
#[deku(ctx = "opcode: u32, subopcode: u32", id = "opcode")]
pub enum ResponsePayload {
#[deku(id = "115")]
LogConfig(#[deku(ctx = "subopcode")] LogConfigResponse),
}
#[derive(Debug, Clone, PartialEq, DekuRead)]
#[deku(ctx = "subopcode: u32", id = "subopcode")]
pub enum LogConfigResponse {
#[deku(id = "1")]
RetrieveIdRanges {
log_mask_sizes: [u32; 16],
},
#[deku(id = "3")]
SetMask,
}
pub fn build_log_mask_request(log_type: u32, log_mask_bitsize: u32, accepted_log_codes: &[u32]) -> Request {
let mut current_byte: u8 = 0;
let mut num_bits_written: u8 = 0;
let mut log_mask: Vec<u8> = vec![];
for i in 0..log_mask_bitsize {
let log_code: u32 = (log_type << 12) | i;
if accepted_log_codes.contains(&log_code) {
current_byte |= 1 << num_bits_written;
}
num_bits_written += 1;
if num_bits_written == 8 || i == log_mask_bitsize - 1 {
log_mask.push(current_byte);
current_byte = 0;
num_bits_written = 0;
}
}
Request::LogConfig(LogConfigRequest::SetMask {
log_type,
log_mask_bitsize,
log_mask,
})
}
#[cfg(test)]
mod test {
use super::*;
// Just about all of these test cases from manually parsing diag packets w/ QCSuper
#[test]
fn test_request_serialization() {
let req = Request::LogConfig(LogConfigRequest::RetrieveIdRanges);
assert_eq!(req.to_bytes().unwrap(), vec![115, 0, 0, 0, 1, 0, 0, 0]);
let req = Request::LogConfig(LogConfigRequest::SetMask {
log_type: 0,
log_mask_bitsize: 0,
log_mask: vec![],
});
assert_eq!(req.to_bytes().unwrap(), vec![
115, 0, 0, 0,
3, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
]);
}
#[test]
fn test_build_log_mask_request() {
let log_type = 11;
let bitsize = 513;
let req = build_log_mask_request(log_type, bitsize, &crate::diag_device::LOG_CODES_FOR_RAW_PACKET_LOGGING);
assert_eq!(req, Request::LogConfig(LogConfigRequest::SetMask {
log_type: log_type,
log_mask_bitsize: bitsize,
log_mask: vec![
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0,
0x0, 0x0, 0xc, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0,
],
}));
}
#[test]
fn test_request_container() {
let req = RequestContainer {
data_type: DataType::UserSpace,
use_mdm: false,
mdm_field: -1,
hdlc_encapsulated_request: vec![1, 2, 3, 4],
};
assert_eq!(req.to_bytes().unwrap(), vec![
32, 0, 0, 0,
1, 2, 3, 4,
]);
let req = RequestContainer {
data_type: DataType::UserSpace,
use_mdm: true,
mdm_field: -1,
hdlc_encapsulated_request: vec![1, 2, 3, 4],
};
assert_eq!(req.to_bytes().unwrap(), vec![
32, 0, 0, 0,
255, 255, 255, 255,
1, 2, 3, 4,
]);
}
#[test]
fn test_logs() {
let data = vec![
16, 0, 38, 0, 38, 0, 192, 176, 26, 165, 245, 135, 118, 35, 2, 1, 20,
14, 48, 0, 160, 0, 2, 8, 0, 0, 217, 15, 5, 0, 0, 0, 0, 7, 0, 64, 1,
238, 173, 213, 77, 208
];
let msg = Message::from_bytes((&data, 0)).unwrap().1;
assert_eq!(msg, Message::Log {
pending_msgs: 0,
outer_length: 38,
inner_length: 38,
log_type: 0xb0c0,
timestamp: Timestamp { ts: 72659535985485082 },
body: LogBody::LteRrcOtaMessage {
ext_header_version: 20,
packet: LteRrcOtaPacket::V8 {
rrc_rel_maj: 14,
rrc_rel_min: 48,
bearer_id: 0,
phy_cell_id: 160,
earfcn: 2050,
sfn_subfn: 4057,
pdu_num: 5,
sib_mask: 0,
len: 7,
packet: vec![0x40, 0x1, 0xee, 0xad, 0xd5, 0x4d, 0xd0],
},
},
});
}
#[test]
fn test_fuck() {
env_logger::init();
let data = vec![32, 0, 0, 0, 1, 0, 0, 0, 122, 1, 0, 0, 16, 0, 38, 0, 38, 0, 192, 176, 153, 128, 249, 211, 218, 62, 2, 1, 20, 14, 48, 0, 160, 0, 14, 6, 1, 0, 217, 39, 5, 0, 0, 0, 0, 7, 0, 64, 2, 14, 213, 72, 153, 192, 168, 216, 126];
dbg!(MessagesContainer::from_bytes((&data, 0)).unwrap());
}
}

242
src/diag_device.rs Normal file
View File

@@ -0,0 +1,242 @@
use crate::hdlc::{hdlc_encapsulate, hdlc_decapsulate, HdlcError};
use crate::diag::{Message, ResponsePayload, Request, LogConfigRequest, LogConfigResponse, build_log_mask_request, RequestContainer, DataType, MessagesContainer};
use crate::log_codes;
use std::fs::File;
use std::io::Read;
use std::os::fd::AsRawFd;
use thiserror::Error;
use crc::{Crc, Algorithm};
use deku::prelude::*;
pub type DiagResult<T> = Result<T, DiagDeviceError>;
#[derive(Error, Debug)]
pub enum DiagDeviceError {
#[error("IO error {0}")]
IO(#[from] std::io::Error),
#[error("Failed to initialize /dev/diag: {0}")]
InitializationFailed(String),
#[error("Failed to read diag device: {0}")]
DeviceReadFailed(String),
#[error("Nonzero status code {0} for diag request: {1:?}")]
RequestFailed(u32, Request),
#[error("Didn't receive response for request: {0:?}")]
NoResponse(Request),
#[error("HDLC error {0}")]
HdlcError(#[from] HdlcError),
#[error("Deku error {0}")]
DekuError(#[from] DekuError),
}
// this is sorta based on the params qcsuper uses, plus what seems to be used in
// https://github.com/fgsect/scat/blob/f1538b397721df3ab8ba12acd26716abcf21f78b/util.py#L47
pub const CRC_CCITT_ALG: Algorithm<u16> = Algorithm {
poly: 0x1021,
init: 0xffff,
refin: true,
refout: true,
width: 16,
xorout: 0xffff,
check: 0x2189,
residue: 0x0000,
};
pub const LOG_CODES_FOR_RAW_PACKET_LOGGING: [u32; 11] = [
// Layer 2:
log_codes::LOG_GPRS_MAC_SIGNALLING_MESSAGE_C, // 0x5226
// Layer 3:
log_codes::LOG_GSM_RR_SIGNALING_MESSAGE_C, // 0x512f
log_codes::WCDMA_SIGNALLING_MESSAGE, // 0x412f
log_codes::LOG_LTE_RRC_OTA_MSG_LOG_C, // 0xb0c0
log_codes::LOG_NR_RRC_OTA_MSG_LOG_C, // 0xb821
// NAS:
log_codes::LOG_UMTS_NAS_OTA_MESSAGE_LOG_PACKET_C, // 0x713a
log_codes::LOG_LTE_NAS_ESM_OTA_IN_MSG_LOG_C, // 0xb0e2
log_codes::LOG_LTE_NAS_ESM_OTA_OUT_MSG_LOG_C, // 0xb0e3
log_codes::LOG_LTE_NAS_EMM_OTA_IN_MSG_LOG_C, // 0xb0ec
log_codes::LOG_LTE_NAS_EMM_OTA_OUT_MSG_LOG_C, // 0xb0ed
// User IP traffic:
log_codes::LOG_DATA_PROTOCOL_LOGGING_C // 0x11eb
];
const BUFFER_LEN: usize = 1024 * 1024 * 10;
const MEMORY_DEVICE_MODE: i32 = 2;
const DIAG_IOCTL_REMOTE_DEV: u32 = 32;
const DIAG_IOCTL_SWITCH_LOGGING: u32 = 7;
pub struct DiagDevice<'a> {
file: &'a File,
read_buf: Vec<u8>,
use_mdm: i32,
crc: Crc<u16>,
}
impl<'a> DiagDevice<'a> {
pub fn new(file: &'a File) -> DiagResult<Self> {
let fd = file.as_raw_fd();
enable_frame_readwrite(fd, MEMORY_DEVICE_MODE)?;
let use_mdm = determine_use_mdm(fd)?;
Ok(DiagDevice {
read_buf: vec![0; BUFFER_LEN],
file,
crc: Crc::<u16>::new(&CRC_CCITT_ALG),
use_mdm,
})
}
fn parse_response_container(&self, container: MessagesContainer) -> DiagResult<Vec<Message>> {
let mut result = Vec::new();
for msg in container.messages {
for sub_msg in msg.data.split_inclusive(|&b| b == 0x7e) {
match hdlc_decapsulate(&sub_msg, &self.crc) {
Ok(data) => match Message::from_bytes((&data, 0)) {
Ok(((leftover_bytes, _), res)) => {
if leftover_bytes.len() > 0 {
println!("warning: {} leftover bytes when parsing Message", leftover_bytes.len());
}
result.push(res);
},
Err(e) => {
println!("error parsing response: {:?}", e);
println!("{:?}", data);
},
},
Err(err) => {
println!("error decapsulating response: {:?}", err);
println!("{:?}", &sub_msg);
}
}
}
}
Ok(result)
}
pub fn read_response(&mut self) -> DiagResult<Vec<Message>> {
loop {
let bytes_read = self.file.read(&mut self.read_buf).unwrap();
let ((leftover_bytes, _), res_container) = MessagesContainer::from_bytes((&self.read_buf[0..bytes_read], 0))?;
if leftover_bytes.len() > 0 {
println!("warning: {} leftover bytes when parsing MessagesContainer", leftover_bytes.len());
}
if res_container.data_type == DataType::UserSpace {
return self.parse_response_container(res_container);
} else {
println!("skipping non-userspace message...")
}
}
}
pub fn write_request(&mut self, req: &Request) -> DiagResult<()> {
let buf = RequestContainer {
data_type: DataType::UserSpace,
use_mdm: self.use_mdm > 0,
mdm_field: -1,
hdlc_encapsulated_request: hdlc_encapsulate(&req.to_bytes().unwrap(), &self.crc),
}.to_bytes().unwrap();
unsafe {
let fd = self.file.as_raw_fd();
let buf_ptr = buf.as_ptr() as *const libc::c_void;
let ret = libc::write(fd, buf_ptr, buf.len());
if ret < 0 {
let msg = format!("write failed with error code {}", ret);
return Err(DiagDeviceError::DeviceReadFailed(msg));
}
}
Ok(())
}
fn retrieve_id_ranges(&mut self) -> DiagResult<[u32; 16]> {
let req = Request::LogConfig(LogConfigRequest::RetrieveIdRanges);
self.write_request(&req)?;
for msg in self.read_response()? {
match msg {
Message::Log { .. } => println!("skipping log response..."),
Message::Response { payload, status, .. } => match payload {
ResponsePayload::LogConfig(LogConfigResponse::RetrieveIdRanges { log_mask_sizes }) => {
if status != 0 {
return Err(DiagDeviceError::RequestFailed(status, req));
}
return Ok(log_mask_sizes);
},
_ => println!("skipping non-LogConfigResponse response..."),
},
}
}
Err(DiagDeviceError::NoResponse(req))
}
fn set_log_mask(&mut self, log_type: u32, log_mask_bitsize: u32) -> DiagResult<()> {
let req = build_log_mask_request(log_type, log_mask_bitsize, &LOG_CODES_FOR_RAW_PACKET_LOGGING);
self.write_request(&req)?;
for msg in self.read_response()? {
match msg {
Message::Log { .. } => println!("skipping log response..."),
Message::Response { payload, status, .. } => {
if let ResponsePayload::LogConfig(LogConfigResponse::SetMask) = payload {
if status != 0 {
return Err(DiagDeviceError::RequestFailed(status, req));
}
return Ok(());
}
},
}
}
Err(DiagDeviceError::NoResponse(req))
}
pub fn config_logs(&mut self) -> DiagResult<()> {
println!("retrieving diag logging capabilities...");
let log_mask_sizes = self.retrieve_id_ranges()?;
for (log_type, &log_mask_bitsize) in log_mask_sizes.iter().enumerate() {
if log_mask_bitsize > 0 {
self.set_log_mask(log_type as u32, log_mask_bitsize)?;
println!("enabled logging for log type {}", log_type);
}
}
Ok(())
}
}
// Triggers the diag device's debug logging mode
fn enable_frame_readwrite(fd: i32, mode: i32) -> DiagResult<()> {
unsafe {
if libc::ioctl(fd, DIAG_IOCTL_SWITCH_LOGGING.into(), mode, 0, 0, 0) < 0 {
let ret = libc::ioctl(
fd,
DIAG_IOCTL_SWITCH_LOGGING.into(),
&mut [mode, -1, 0] as *mut _, // diag_logging_mode_param_t
std::mem::size_of::<[i32; 3]>(), 0, 0, 0, 0
);
if ret < 0 {
let msg = format!("DIAG_IOCTL_SWITCH_LOGGING ioctl failed with error code {}", ret);
return Err(DiagDeviceError::InitializationFailed(msg))
}
}
}
Ok(())
}
// Unsure of what MDM actually stands for, but if `use_mdm` is > 0, then
// an additional mask is included in every diag request
fn determine_use_mdm(fd: i32) -> DiagResult<i32> {
let use_mdm: i32 = 0;
unsafe {
if libc::ioctl(fd, DIAG_IOCTL_REMOTE_DEV.into(), &use_mdm as *const i32) < 0 {
let msg = format!("DIAG_IOCTL_REMOTE_DEV ioctl failed with error code {}", 0);
return Err(DiagDeviceError::InitializationFailed(msg))
}
}
Ok(use_mdm)
}

97
src/hdlc.rs Normal file
View File

@@ -0,0 +1,97 @@
//! HDLC stands for "High-level Data Link Control", which the diag protocol uses
//! to encapsulate its messages. QCSuper's docs describe this in more detail
//! here:
//! https://github.com/P1sec/QCSuper/blob/master/docs/The%20Diag%20protocol.md#the-diag-protocol-over-usb
use crc::Crc;
use bytes::Buf;
use thiserror::Error;
#[derive(Debug, Error, PartialEq)]
pub enum HdlcError {
#[error("Invalid checksum (expected {0}, got {1})")]
InvalidChecksum(u16, u16),
#[error("Invalid HDLC escape sequence: [0x7d, {0}]")]
InvalidEscapeSequence(u8),
#[error("No trailing character found (expected 0x7e, got {0}))")]
NoTrailingCharacter(u8),
#[error("Missing checksum")]
MissingChecksum,
#[error("Data too short to be HDLC encapsulated")]
TooShort,
}
pub fn hdlc_encapsulate(data: &[u8], crc: &Crc<u16>) -> Vec<u8> {
let mut result: Vec<u8> = vec![];
for &b in data {
match b {
0x7e => result.extend([0x7d, 0x5e]),
0x7d => result.extend([0x7d, 0x5d]),
_ => result.push(b),
}
}
for b in crc.checksum(&data).to_le_bytes() {
match b {
0x7e => result.extend([0x7d, 0x5e]),
0x7d => result.extend([0x7d, 0x5d]),
_ => result.push(b),
}
}
result.push(0x7e);
result
}
pub fn hdlc_decapsulate(data: &[u8], crc: &Crc<u16>) -> Result<Vec<u8>, HdlcError> {
if data.len() < 3 {
return Err(HdlcError::TooShort);
}
if data[data.len() - 1] != 0x7e {
return Err(HdlcError::NoTrailingCharacter(data[data.len() - 1]));
}
let mut unescaped = Vec::new();
let mut escaping = false;
for &b in &data[..data.len() - 1] {
if escaping {
match b {
0x5e => unescaped.push(0x7e),
0x5d => unescaped.push(0x7d),
_ => return Err(HdlcError::InvalidEscapeSequence(b)),
}
escaping = false;
} else if b == 0x7d {
escaping = true
} else {
unescaped.push(b);
}
}
// pop off the u16 checksum, check it against what we calculated
let checksum_hi = unescaped.pop().ok_or(HdlcError::MissingChecksum)?;
let checksum_lo = unescaped.pop().ok_or(HdlcError::MissingChecksum)?;
let checksum = [checksum_lo, checksum_hi].as_slice().get_u16_le();
if checksum != crc.checksum(&unescaped) {
return Err(HdlcError::InvalidChecksum(checksum, crc.checksum(&unescaped)));
}
Ok(unescaped)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hdlc_encapsulate() {
let crc = Crc::<u16>::new(&crate::diag_device::CRC_CCITT_ALG);
let data = vec![0x01, 0x02, 0x03, 0x04];
let expected = vec![1, 2, 3, 4, 145, 57, 126];
let encapsulated = hdlc_encapsulate(&data, &crc);
assert_eq!(&encapsulated, &expected);
assert_eq!(hdlc_decapsulate(&encapsulated, &crc), Ok(data));
}
}

108
src/log_codes.rs Normal file
View File

@@ -0,0 +1,108 @@
//! Enumerates some releVant diag log codes. Copied from QCSuper
// These are 2G-related log types.
pub const LOG_GSM_RR_SIGNALING_MESSAGE_C: u32 = 0x512f;
pub const DCCH: u32 = 0x00;
pub const BCCH: u32 = 0x01;
pub const L2_RACH: u32 = 0x02;
pub const CCCH: u32 = 0x03;
pub const SACCH: u32 = 0x04;
pub const SDCCH: u32 = 0x05;
pub const FACCH_F: u32 = 0x06;
pub const FACCH_H: u32 = 0x07;
pub const L2_RACH_WITH_NO_DELAY: u32 = 0x08;
// These are GPRS-related log types.
pub const LOG_GPRS_MAC_SIGNALLING_MESSAGE_C: u32 = 0x5226;
pub const PACCH_RRBP_CHANNEL: u32 = 0x03;
pub const UL_PACCH_CHANNEL: u32 = 0x04;
pub const DL_PACCH_CHANNEL: u32 = 0x83;
pub const PACKET_CHANNEL_REQUEST: u32 = 0x20;
// These are 5G-related log types.
pub const LOG_NR_RRC_OTA_MSG_LOG_C: u32 = 0xb821;
// These are 4G-related log types.
pub const LOG_LTE_RRC_OTA_MSG_LOG_C: u32 = 0xb0c0;
pub const LOG_LTE_NAS_ESM_OTA_IN_MSG_LOG_C: u32 = 0xb0e2;
pub const LOG_LTE_NAS_ESM_OTA_OUT_MSG_LOG_C: u32 = 0xb0e3;
pub const LOG_LTE_NAS_EMM_OTA_IN_MSG_LOG_C: u32 = 0xb0ec;
pub const LOG_LTE_NAS_EMM_OTA_OUT_MSG_LOG_C: u32 = 0xb0ed;
pub const LTE_BCCH_BCH_V0: u32 = 1;
pub const LTE_BCCH_DL_SCH_V0: u32 = 2;
pub const LTE_MCCH_V0: u32 = 3;
pub const LTE_PCCH_V0: u32 = 4;
pub const LTE_DL_CCCH_V0: u32 = 5;
pub const LTE_DL_DCCH_V0: u32 = 6;
pub const LTE_UL_CCCH_V0: u32 = 7;
pub const LTE_UL_DCCH_V0: u32 = 8;
pub const LTE_BCCH_BCH_V14: u32 = 1;
pub const LTE_BCCH_DL_SCH_V14: u32 = 2;
pub const LTE_MCCH_V14: u32 = 4;
pub const LTE_PCCH_V14: u32 = 5;
pub const LTE_DL_CCCH_V14: u32 = 6;
pub const LTE_DL_DCCH_V14: u32 = 7;
pub const LTE_UL_CCCH_V14: u32 = 8;
pub const LTE_UL_DCCH_V14: u32 = 9;
pub const LTE_BCCH_BCH_V9: u32 = 8;
pub const LTE_BCCH_DL_SCH_V9: u32 = 9;
pub const LTE_MCCH_V9: u32 = 10;
pub const LTE_PCCH_V9: u32 = 11;
pub const LTE_DL_CCCH_V9: u32 = 12;
pub const LTE_DL_DCCH_V9: u32 = 13;
pub const LTE_UL_CCCH_V9: u32 = 14;
pub const LTE_UL_DCCH_V9: u32 = 15;
pub const LTE_BCCH_BCH_V19: u32 = 1;
pub const LTE_BCCH_DL_SCH_V19: u32 = 3;
pub const LTE_MCCH_V19: u32 = 6;
pub const LTE_PCCH_V19: u32 = 7;
pub const LTE_DL_CCCH_V19: u32 = 8;
pub const LTE_DL_DCCH_V19: u32 = 9;
pub const LTE_UL_CCCH_V19: u32 = 10;
pub const LTE_UL_DCCH_V19: u32 = 11;
pub const LTE_BCCH_BCH_NB: u32 = 45;
pub const LTE_BCCH_DL_SCH_NB: u32 = 46;
pub const LTE_PCCH_NB: u32 = 47;
pub const LTE_DL_CCCH_NB: u32 = 48;
pub const LTE_DL_DCCH_NB: u32 = 49;
pub const LTE_UL_CCCH_NB: u32 = 50;
pub const LTE_UL_DCCH_NB: u32 = 52;
// These are 3G-related log types.
pub const RRCLOG_SIG_UL_CCCH: u32 = 0;
pub const RRCLOG_SIG_UL_DCCH: u32 = 1;
pub const RRCLOG_SIG_DL_CCCH: u32 = 2;
pub const RRCLOG_SIG_DL_DCCH: u32 = 3;
pub const RRCLOG_SIG_DL_BCCH_BCH: u32 = 4;
pub const RRCLOG_SIG_DL_BCCH_FACH: u32 = 5;
pub const RRCLOG_SIG_DL_PCCH: u32 = 6;
pub const RRCLOG_SIG_DL_MCCH: u32 = 7;
pub const RRCLOG_SIG_DL_MSCH: u32 = 8;
pub const RRCLOG_EXTENSION_SIB: u32 = 9;
pub const RRCLOG_SIB_CONTAINER: u32 = 10;
// 3G layer 3 packets:
pub const WCDMA_SIGNALLING_MESSAGE: u32 = 0x412f;
// Upper layers
pub const LOG_DATA_PROTOCOL_LOGGING_C: u32 = 0x11eb;
pub const LOG_UMTS_NAS_OTA_MESSAGE_LOG_PACKET_C: u32 = 0x713a;

View File

@@ -1,200 +1,24 @@
use std::fs::File;
use std::io::{Cursor, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use bytes::{Buf, BufMut};
use std::os::fd::AsRawFd;
use std::thread;
use thiserror::Error;
mod hdlc;
mod diag;
mod diag_device;
mod log_codes;
type DiagResult<T> = Result<T, DiagDeviceError>;
use crate::diag_device::DiagDevice;
const BUFFER_LEN: usize = 1024 * 1024 * 10;
const USER_SPACE_DATA_TYPE: i32 = 32;
const DIAG_IOCTL_REMOTE_DEV: u32 = 32;
const MEMORY_DEVICE_MODE: i32 = 2;
const DIAG_IOCTL_SWITCH_LOGGING: u32 = 7;
fn main() -> diag_device::DiagResult<()> {
// this should eventually be removed for prod
env_logger::init();
#[derive(Error, Debug)]
enum DiagDeviceError {
#[error("IO error {0}")]
IO(#[from] std::io::Error),
#[error("Failed to initialize /dev/diag: {0}")]
InitializationFailed(String),
#[error("Failed to read diag device: {0}")]
DeviceReadFailed(String),
}
struct DiagDevice {
file: File,
use_mdm: i32,
}
// Triggers the diag device's debug logging mode
fn enable_frame_readwrite(fd: i32, mode: i32) -> DiagResult<()> {
unsafe {
if libc::ioctl(fd, DIAG_IOCTL_SWITCH_LOGGING, mode, 0, 0, 0) < 0 {
let ret = libc::ioctl(
fd,
DIAG_IOCTL_SWITCH_LOGGING,
&mut [mode, -1, 0] as *mut _, // diag_logging_mode_param_t
std::mem::size_of::<[i32; 3]>(), 0, 0, 0, 0
);
if ret < 0 {
let msg = format!("DIAG_IOCTL_SWITCH_LOGGING ioctl failed with error code {}", ret);
return Err(DiagDeviceError::InitializationFailed(msg))
}
}
}
Ok(())
}
// Unsure of what MDM actually stands for, but if `use_mdm` is > 0, then
// an additional mask is included in every diag request
fn determine_use_mdm(fd: i32) -> DiagResult<i32> {
let use_mdm: i32 = 0;
unsafe {
if libc::ioctl(fd, DIAG_IOCTL_REMOTE_DEV, &use_mdm as *const i32) < 0 {
let msg = format!("DIAG_IOCTL_REMOTE_DEV ioctl failed with error code {}", 0);
return Err(DiagDeviceError::InitializationFailed(msg))
}
}
Ok(use_mdm)
}
impl DiagDevice {
pub fn new() -> DiagResult<Self> {
let file = File::options()
let file = std::fs::File::options()
.read(true)
.write(true)
.open("/dev/diag")?;
let fd = file.as_raw_fd();
let mut dev = DiagDevice::new(&file)?;
dev.config_logs()?;
enable_frame_readwrite(fd, MEMORY_DEVICE_MODE)?;
let use_mdm = determine_use_mdm(fd)?;
Ok(DiagDevice {
file,
use_mdm,
})
}
pub fn try_clone(&self) -> DiagResult<Self> {
Ok(DiagDevice {
file: self.file.try_clone()?,
use_mdm: self.use_mdm,
})
}
pub fn read_response(&mut self) -> DiagResult<Option<Vec<Vec<u8>>>> {
let mut buf = vec![0; BUFFER_LEN];
let bytes_read = self.file.read(&mut buf)?;
if bytes_read < 4 {
let msg = format!("read {} bytes from diag device, expected > 4", bytes_read);
return Err(DiagDeviceError::DeviceReadFailed(msg));
}
let mut reader = Cursor::new(buf);
if reader.get_i32_le() != USER_SPACE_DATA_TYPE {
return Ok(None);
}
let num_messages = reader.get_u32_le();
let mut messages = Vec::new();
for _ in 0..num_messages {
let msg_len = reader.get_u32_le() as usize;
let mut msg = vec![0; msg_len];
reader.read_exact(&mut msg)?;
messages.push(msg);
}
Ok(Some(messages))
}
pub fn write_request(&mut self, req: &[u8]) -> DiagResult<()> {
let mut buf: Vec<u8> = vec![];
buf.put_i32_le(USER_SPACE_DATA_TYPE);
if self.use_mdm > 0 {
buf.put_i32_le(-1);
}
buf.extend_from_slice(req);
unsafe {
let fd = self.file.as_raw_fd();
let buf_ptr = buf.as_ptr() as *const libc::c_void;
let ret = libc::write(fd, buf_ptr, buf.len());
if ret < 0 {
let msg = format!("write failed with error code {}", ret);
return Err(DiagDeviceError::DeviceReadFailed(msg));
}
}
Ok(())
}
}
fn main() -> std::io::Result<()> {
println!("Starting server");
let listener = TcpListener::bind("0.0.0.0:43555")?;
// Since we only care about one client at a time, store a copy of that
// client's TcpStream in a mutex. This lets us write to the client from a
// separate thread
let client_mutex: Arc<Mutex<Option<TcpStream>>> = Arc::new(Mutex::new(None));
// initialize the diag device and create a cloned handle to its file. this
// lets us perform reads and writes in separate threads. i *think* this is
// sound
let mut dev_reader = DiagDevice::new().unwrap();
let mut dev_writer = dev_reader.try_clone().unwrap();
// Spawn a thread to continuously read from the diag device, sending any
// messages to the client
let client_mutex_clone = client_mutex.clone();
thread::spawn(move || {
loop {
match dev_reader.read_response() {
Ok(Some(msgs)) => {
if let Some(client_writer) = client_mutex_clone.lock().unwrap().as_mut() {
println!("> Writing {} diag messages to client", msgs.len());
for msg in msgs {
client_writer.write_all(&msg).unwrap();
}
}
},
Ok(None) => {},
Err(err) => {
println!("Unable to read from /dev/diag: {}", err);
return;
},
}
}
});
// Accept connections from clients, writing any data received to the diag device
loop {
println!("Waiting for client");
let (mut client_reader, _) = listener.accept()?;
println!("Client connected");
let client_writer = client_reader.try_clone()?;
{
let mut client_writer_mutex = client_mutex.lock().unwrap();
*client_writer_mutex = Some(client_writer);
}
let mut buf = vec![0; BUFFER_LEN];
loop {
let bytes_read = client_reader.read(&mut buf).unwrap();
if bytes_read == 0 {
println!("Client disconnected");
{
let mut client_writer_mutex = client_mutex.lock().unwrap();
*client_writer_mutex = None;
}
break;
}
println!("< Got {} bytes from client", bytes_read);
dev_writer.write_request(&buf[0..bytes_read]).unwrap();
for msg in dev.read_response()? {
println!("msg: {:?}", msg);
}
}
}