burp: Begin BURP stats client implementation
The `burp` module contains an implementation of a BURP stats client. It uses *tokio* for asynchronous network communication with the BURP stats TCP socket. The `ClientConnector` struct follows the builder pattern for specifying connection options, ultimately producing a `Client` struct that manages communication over the socket. BURP uses mutual TLS authentication for all its communication. The client authenticates the server by verifying its certificate using a trusted CA certificate. This certificate is not usually trusted system-wide, but specifically by BURP clients. The server also authenticates the client using a certificate. The official BURP client uses a normal PEM-encoded X.509 certificate and PKCS #8 key, however, the *native-tls* library does not support loading these. As such, the certificate and private key must be encapsulated in a PKCS #12 container.
parent
727aaa6b8f
commit
ce3b9703bd
|
@ -2,6 +2,528 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "burp_exporter"
|
name = "burp_exporter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"openssl",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.72"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.7.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"miow",
|
||||||
|
"ntapi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miow"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.72"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.2.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"remove_dir_all",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"mio",
|
||||||
|
"once_cell",
|
||||||
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"tokio-macros",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74786ce43333fcf51efe947aed9718fbe46d5c7328ec3f1029e818083966d9aa"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"lazy_static",
|
||||||
|
"matchers",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[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-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -6,3 +6,14 @@ license = "MIT OR Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
openssl = "^0.10.38"
|
||||||
|
tokio-native-tls = "^0.3.0"
|
||||||
|
tracing = "^0.1.30"
|
||||||
|
|
||||||
|
[dependencies.tokio]
|
||||||
|
version = "^1.16.1"
|
||||||
|
features = ["io-util", "macros", "net", "rt", "signal"]
|
||||||
|
|
||||||
|
[dependencies.tracing-subscriber]
|
||||||
|
version = "^0.3.8"
|
||||||
|
features = ["env-filter"]
|
||||||
|
|
|
@ -0,0 +1,259 @@
|
||||||
|
//! BURP client
|
||||||
|
use std::char;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio_native_tls::native_tls::TlsConnector as NativeTlsConnector;
|
||||||
|
use tokio_native_tls::native_tls::{Certificate, Identity, Protocol};
|
||||||
|
use tokio_native_tls::TlsConnector;
|
||||||
|
use tokio_native_tls::TlsStream;
|
||||||
|
use tracing::{debug, info, trace};
|
||||||
|
|
||||||
|
use super::error::Error;
|
||||||
|
|
||||||
|
/// The BURP client version emulated by this implementation
|
||||||
|
const CLIENT_VERSION: &str = "2.1.32";
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! unexpected_response {
|
||||||
|
($msg:ident) => {
|
||||||
|
Err(Error::Protocol(format!(
|
||||||
|
"Unexpected response from server: {}",
|
||||||
|
$msg,
|
||||||
|
)))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specify client connection options using the builder pattern
|
||||||
|
///
|
||||||
|
/// To connect to a BURP server, create a [`ClientConnector`] and use
|
||||||
|
/// its methods to specify connection options. After all options have
|
||||||
|
/// been set, call [`ClientConnector::connect`] to initiate the
|
||||||
|
/// connection.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let mut client = ClientConnector::new("::1")
|
||||||
|
/// .port(49720)
|
||||||
|
/// .server_name("burp.example.org")
|
||||||
|
/// .ca_cert(cert)
|
||||||
|
/// .connect()
|
||||||
|
/// .await?;
|
||||||
|
/// ```
|
||||||
|
pub struct ClientConnector {
|
||||||
|
host: String,
|
||||||
|
port: u16,
|
||||||
|
server_name: Option<String>,
|
||||||
|
ca_cert: Option<Certificate>,
|
||||||
|
identity: Option<Identity>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientConnector {
|
||||||
|
/// Create a new client connector
|
||||||
|
///
|
||||||
|
/// `host` is the string hostname or IP address of the server
|
||||||
|
pub fn new(host: impl Into<String>) -> Self {
|
||||||
|
ClientConnector {
|
||||||
|
host: host.into(),
|
||||||
|
port: 4972,
|
||||||
|
server_name: None,
|
||||||
|
ca_cert: None,
|
||||||
|
identity: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the server port
|
||||||
|
pub fn port(mut self, port: u16) -> Self {
|
||||||
|
self.port = port;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the CA certificate used to verify the server's certificate
|
||||||
|
pub fn ca_cert(mut self, cert: Certificate) -> Self {
|
||||||
|
self.ca_cert = Some(cert);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the CA certificate from a file
|
||||||
|
///
|
||||||
|
/// This method may return an error if the certificate could not be
|
||||||
|
/// loaded from the specified file.
|
||||||
|
pub fn ca_cert_file(self, path: impl AsRef<Path>) -> Result<Self, Error> {
|
||||||
|
let mut f = File::open(path)?;
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
f.read_to_end(&mut buf)?;
|
||||||
|
Ok(self.ca_cert(Certificate::from_pem(&buf)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the certificate and private key for client authentication
|
||||||
|
pub fn identity(mut self, identity: Identity) -> Self {
|
||||||
|
self.identity = Some(identity);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the certificate and private key from a file
|
||||||
|
///
|
||||||
|
/// This method may return an error if the certificate or private
|
||||||
|
/// key could not be loaded from the specified file, or the file is
|
||||||
|
/// not a valid PKCS#12 container.
|
||||||
|
pub fn identity_file(
|
||||||
|
self,
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
password: &str,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let mut f = File::open(path)?;
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
f.read_to_end(&mut buf)?;
|
||||||
|
Ok(self.identity(Identity::from_pkcs12(&buf, password)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the name of the server to use for certificate validation
|
||||||
|
///
|
||||||
|
/// If the name used to connect to the server does not match any of
|
||||||
|
/// the names on its certificate, this method can be used to specify
|
||||||
|
/// the expected name.
|
||||||
|
pub fn server_name(mut self, name: impl Into<String>) -> Self {
|
||||||
|
self.server_name = Some(name.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Connect to the server
|
||||||
|
///
|
||||||
|
/// Returns an [`Error`] if the connection could not be established
|
||||||
|
/// for any reason (e.g. name does not resolve, address is
|
||||||
|
/// unreachable, TLS handshake fails, etc.)
|
||||||
|
pub async fn connect(self) -> Result<Client, Error> {
|
||||||
|
let stream =
|
||||||
|
TcpStream::connect((self.host.as_ref(), self.port)).await?;
|
||||||
|
info!(
|
||||||
|
"Successfully connected to {}, port {}",
|
||||||
|
&self.host, self.port
|
||||||
|
);
|
||||||
|
let mut builder = NativeTlsConnector::builder();
|
||||||
|
builder.min_protocol_version(Some(Protocol::Tlsv12));
|
||||||
|
if let Some(ca_cert) = self.ca_cert {
|
||||||
|
builder.add_root_certificate(ca_cert);
|
||||||
|
}
|
||||||
|
if let Some(identity) = self.identity {
|
||||||
|
builder.identity(identity);
|
||||||
|
}
|
||||||
|
let conn: TlsConnector = builder.build()?.into();
|
||||||
|
let socket = conn
|
||||||
|
.connect(&self.server_name.unwrap_or(self.host), stream)
|
||||||
|
.await?;
|
||||||
|
Ok(Client { socket })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// BURP stats client
|
||||||
|
pub struct Client {
|
||||||
|
socket: TlsStream<TcpStream>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
/// Perform the initial handshake and authentication
|
||||||
|
///
|
||||||
|
/// * `name`: The BURP client name (must match certificate)
|
||||||
|
/// * `password`: (Optional) The client password; use `None` to
|
||||||
|
/// avoid sending a password to the server
|
||||||
|
///
|
||||||
|
/// If the handshake fails, [`Error`] is returned.
|
||||||
|
pub async fn handshake(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
password: Option<&str>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let res = self
|
||||||
|
.command('c', &format!("hello:{}", CLIENT_VERSION))
|
||||||
|
.await?;
|
||||||
|
let mut parts = res.split(':');
|
||||||
|
if let Some(msg) = parts.next() {
|
||||||
|
if msg != "whoareyou" {
|
||||||
|
return unexpected_response!(res);
|
||||||
|
}
|
||||||
|
if let Some(version) = parts.next() {
|
||||||
|
info!("Server version: {}", version);
|
||||||
|
if version.is_empty() {
|
||||||
|
return Err(Error::UnsupportedVersion(
|
||||||
|
"Unknown server version".into(),
|
||||||
|
));
|
||||||
|
} else if !version.starts_with('2') {
|
||||||
|
return Err(Error::UnsupportedVersion(format!(
|
||||||
|
"Unsupported server version: {}",
|
||||||
|
version
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return unexpected_response!(res);
|
||||||
|
}
|
||||||
|
let res = self.command('c', name).await?;
|
||||||
|
if res != "okpassword" {
|
||||||
|
return unexpected_response!(res);
|
||||||
|
}
|
||||||
|
if let Some(password) = password {
|
||||||
|
let res = self.command('c', password).await?;
|
||||||
|
if res != "ok" {
|
||||||
|
return unexpected_response!(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res = self.command('c', "nocsr").await?;
|
||||||
|
if res != "nocsr ok" {
|
||||||
|
return unexpected_response!(res);
|
||||||
|
}
|
||||||
|
let res = self.command('c', "extra_comms_begin").await?;
|
||||||
|
let mut parts = res.split_terminator(':');
|
||||||
|
if let Some(msg) = parts.next() {
|
||||||
|
if msg != "extra_comms_begin ok" {
|
||||||
|
return unexpected_response!(msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return unexpected_response!(res);
|
||||||
|
}
|
||||||
|
let capabilities: Vec<&str> = parts.collect();
|
||||||
|
info!("Server capabilities: {:?}", capabilities);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a command to the server
|
||||||
|
///
|
||||||
|
/// * `command`: BURP command (usually `c`)
|
||||||
|
/// * `data`: Data to send with the command, if applicable
|
||||||
|
///
|
||||||
|
/// If the server returns a successful (`c`) response, its data
|
||||||
|
/// will be returned as a string. If it returns an error (`e`)
|
||||||
|
/// response, its data will be returned in an [`Error`].
|
||||||
|
pub async fn command(
|
||||||
|
&mut self,
|
||||||
|
command: char,
|
||||||
|
data: &str,
|
||||||
|
) -> Result<String, Error> {
|
||||||
|
debug!("Sending command {} {}", &command, &data);
|
||||||
|
let msg = format!("{}{:>04X}{}\0", &command, data.len() + 1, &data);
|
||||||
|
trace!("Sending {:?}", msg);
|
||||||
|
self.socket.write_all(msg.as_bytes()).await?;
|
||||||
|
let mut buf = [0; 5];
|
||||||
|
self.socket.read_exact(&mut buf).await?;
|
||||||
|
trace!("Got response header {:?}", str::from_utf8(&buf));
|
||||||
|
let msgtype = buf[0];
|
||||||
|
let sz = usize::from_str_radix(str::from_utf8(&buf[1..]).unwrap(), 16)
|
||||||
|
.unwrap();
|
||||||
|
trace!("Response body length: {} bytes", sz);
|
||||||
|
let mut buf = vec![0; sz];
|
||||||
|
self.socket.read_exact(&mut buf).await?;
|
||||||
|
let response = String::from_utf8(buf).unwrap();
|
||||||
|
debug!("Server response: {} {}", char::from(msgtype), &response);
|
||||||
|
match msgtype {
|
||||||
|
b'c' => Ok(response),
|
||||||
|
b'e' => Err(Error::Command(response)),
|
||||||
|
_ => {
|
||||||
|
panic!("don't know what to do with {:?}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
//! Client error handling
|
||||||
|
use std::io;
|
||||||
|
use tokio_native_tls::native_tls;
|
||||||
|
|
||||||
|
/// BURP client errors
|
||||||
|
///
|
||||||
|
/// Most functions and methods in this module return this error type.
|
||||||
|
/// Depending on the cause of the error, a more specific error type may
|
||||||
|
/// be encapsulated.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// An I/O (e.g. file, network) error has occurred
|
||||||
|
Io(io::Error),
|
||||||
|
/// A TLS error has occurred
|
||||||
|
Tls(native_tls::Error),
|
||||||
|
/// The BURP server returned an error response to a command
|
||||||
|
Command(String),
|
||||||
|
/// The BURP server did not return the expected response
|
||||||
|
Protocol(String),
|
||||||
|
/// The version of the BURP server is not supported
|
||||||
|
UnsupportedVersion(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(error: io::Error) -> Self {
|
||||||
|
Self::Io(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<native_tls::Error> for Error {
|
||||||
|
fn from(error: native_tls::Error) -> Self {
|
||||||
|
Self::Tls(error)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
//! BURP Stats Client
|
||||||
|
//!
|
||||||
|
//! This module provides a client implementation for the BURP stats
|
||||||
|
//! socket protocol. It can be used to connect to the stats socket of a
|
||||||
|
//! BURP server and retrieve statistics about BURP clients and their
|
||||||
|
//! backups.
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
pub mod client;
|
||||||
|
pub mod error;
|
Loading…
Reference in New Issue