first commit
This commit is contained in:
commit
26bbb6e55c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
841
Cargo.lock
generated
Normal file
841
Cargo.lock
generated
Normal file
@ -0,0 +1,841 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ax25"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fec6189a57a9668a17aa3368d110b1451450df47b85200f43d93357fb21f3b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axtun"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"ax25",
|
||||||
|
"clap",
|
||||||
|
"etherparse",
|
||||||
|
"futures",
|
||||||
|
"tokio",
|
||||||
|
"tun",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||||
|
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 = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "c2rust-bitfields"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b43c3f07ab0ef604fa6f595aa46ec2f8a22172c975e186f6f5bf9829a3b72c41"
|
||||||
|
dependencies = [
|
||||||
|
"c2rust-bitfields-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "c2rust-bitfields-derive"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3cbc102e2597c9744c8bd8c15915d554300601c91a079430d309816b0912545"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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 = "clap"
|
||||||
|
version = "4.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "etherparse"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "827292ea592108849932ad8e30218f8b1f21c0dfd0696698a18b5d0aed62d990"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
|
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.28.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ioctl-sys"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.153"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.8.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.32.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.78"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||||
|
|
||||||
|
[[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.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.36.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
|
"parking_lot",
|
||||||
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tun"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0adb9992bbd5ca76f3847ed579ad4ee8defb2ec2eea918cceef17ccc66fa4fd4"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"ioctl-sys",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"wintun",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.51.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core",
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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 = "wintun"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29b83b0eca06dd125dbcd48a45327c708a6da8aada3d95a3f06db0ce4b17e0d4"
|
||||||
|
dependencies = [
|
||||||
|
"c2rust-bitfields",
|
||||||
|
"libloading",
|
||||||
|
"log",
|
||||||
|
"thiserror",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "axtun"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.78"
|
||||||
|
ax25 = "0.3.0"
|
||||||
|
clap = { version = "4.4.13", features = ["derive"] }
|
||||||
|
etherparse = "0.13.0"
|
||||||
|
futures = "0.3.30"
|
||||||
|
tokio = { version = "1.35.1", features = ["full"] }
|
||||||
|
tun = { version = "0.6.1", features = ["tokio", "async"] }
|
||||||
687
src/arp.rs
Normal file
687
src/arp.rs
Normal file
@ -0,0 +1,687 @@
|
|||||||
|
use crate::tools::AxAddrOctets;
|
||||||
|
use crate::tools::Mask;
|
||||||
|
use crate::tools::PoppableParser;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use ax25::frame::Address;
|
||||||
|
use ax25::frame::Ax25Frame;
|
||||||
|
use ax25::frame::FrameContent;
|
||||||
|
use ax25::frame::ProtocolIdentifier;
|
||||||
|
use ax25::frame::UnnumberedInformation;
|
||||||
|
|
||||||
|
use etherparse::InternetSlice;
|
||||||
|
use etherparse::Ipv4HeaderSlice;
|
||||||
|
use etherparse::SlicedPacket;
|
||||||
|
use etherparse::TransportSlice;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
const MAX_BUFFERED_PKTS: usize = 6;
|
||||||
|
const ARP_PENDING_TTL: Duration = Duration::from_secs(60);
|
||||||
|
const ARP_CACHE_TTL: Duration = Duration::from_secs(120);
|
||||||
|
|
||||||
|
pub struct ArpPacket {
|
||||||
|
htype: u16,
|
||||||
|
ptype: u16,
|
||||||
|
hlen: u8,
|
||||||
|
plen: u8,
|
||||||
|
oper: u16,
|
||||||
|
sha: Vec<u8>,
|
||||||
|
spa: Vec<u8>,
|
||||||
|
tha: Vec<u8>,
|
||||||
|
tpa: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArpPacket {
|
||||||
|
/// ARP htype for AX.25
|
||||||
|
const AX_HTYPE: [u8; 2] = [0, 3];
|
||||||
|
/// AX.25 Protocol Identifier for arpa ip
|
||||||
|
const AX_ARPA_IP: [u8; 2] = [0, 0xCC];
|
||||||
|
/// AX.25 address length in octets
|
||||||
|
const AX_HLEN: u8 = 7;
|
||||||
|
/// IPv4 address length in octets
|
||||||
|
const IP_PLEN: u8 = 4;
|
||||||
|
|
||||||
|
pub fn from_bytes(mut bytes: &[u8]) -> Result<Self> {
|
||||||
|
let htype = bytes.pop_u16()?;
|
||||||
|
let ptype = bytes.pop_u16()?;
|
||||||
|
let hlen = bytes.pop_u8()?;
|
||||||
|
let plen = bytes.pop_u8()?;
|
||||||
|
Ok(Self {
|
||||||
|
htype,
|
||||||
|
ptype,
|
||||||
|
hlen,
|
||||||
|
plen,
|
||||||
|
oper: bytes.pop_u16()?,
|
||||||
|
sha: bytes.pop_bytes(hlen as usize)?,
|
||||||
|
spa: bytes.pop_bytes(plen as usize)?,
|
||||||
|
tha: bytes.pop_bytes(hlen as usize)?,
|
||||||
|
tpa: bytes.pop_bytes(plen as usize)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn ax_request_raw(ax_src: &Address, ip_src: Ipv4Addr, ip_dest: Ipv4Addr) -> Vec<u8> {
|
||||||
|
let htype = 0x03; // ARP htype for AX25
|
||||||
|
let ptype = 0xCC; // AX25 protocolIdentifier for IP
|
||||||
|
let hlen = 7; // Ax25 address length in octets
|
||||||
|
let plen = 4; // IPv4 address length in octets
|
||||||
|
let mut v: Vec<u8> = vec![0, htype, 0, ptype, hlen, plen, 0, 1];
|
||||||
|
|
||||||
|
v.append(&mut ax_src.octets().to_vec());
|
||||||
|
v.append(&mut ip_src.octets().to_vec());
|
||||||
|
|
||||||
|
v.append(&mut vec![0_u8; hlen as usize]);
|
||||||
|
v.append(&mut ip_dest.octets().to_vec());
|
||||||
|
v
|
||||||
|
}
|
||||||
|
/*fn ax25_raw(
|
||||||
|
ax_src: &Address,
|
||||||
|
ip_src: &Ipv4Addr,
|
||||||
|
ax_dest: &Address,
|
||||||
|
ip_dest: &Ipv4Addr,
|
||||||
|
oper: u16,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let mut v: Vec<u8> = vec![
|
||||||
|
Self::AX_HTYPE[0],
|
||||||
|
Self::AX_HTYPE[1],
|
||||||
|
Self::AX_ARPA_IP[0],
|
||||||
|
Self::AX_ARPA_IP[1],
|
||||||
|
Self::AX_HLEN,
|
||||||
|
Self::IP_PLEN,
|
||||||
|
((oper >> 8) & 0xFF) as u8,
|
||||||
|
(oper & 0xFF) as u8,
|
||||||
|
];
|
||||||
|
|
||||||
|
v.append(&mut ax_src.octets().to_vec());
|
||||||
|
v.append(&mut ip_src.octets().to_vec());
|
||||||
|
|
||||||
|
v.append(&mut ax_dest.octets().to_vec());
|
||||||
|
v.append(&mut ip_dest.octets().to_vec());
|
||||||
|
v
|
||||||
|
}*/
|
||||||
|
fn ax25_zip(
|
||||||
|
ax_src: &[u8; Self::AX_HLEN as usize],
|
||||||
|
ip_src: &[u8; Self::IP_PLEN as usize],
|
||||||
|
ax_dest: &[u8; Self::AX_HLEN as usize],
|
||||||
|
ip_dest: &[u8; Self::IP_PLEN as usize],
|
||||||
|
oper: u16,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let mut v: Vec<u8> = vec![
|
||||||
|
Self::AX_HTYPE[0],
|
||||||
|
Self::AX_HTYPE[1],
|
||||||
|
Self::AX_ARPA_IP[0],
|
||||||
|
Self::AX_ARPA_IP[1],
|
||||||
|
Self::AX_HLEN,
|
||||||
|
Self::IP_PLEN,
|
||||||
|
((oper >> 8) & 0xFF) as u8,
|
||||||
|
(oper & 0xFF) as u8,
|
||||||
|
];
|
||||||
|
|
||||||
|
v.append(&mut ax_src.to_vec());
|
||||||
|
v.append(&mut ip_src.to_vec());
|
||||||
|
|
||||||
|
v.append(&mut ax_dest.to_vec());
|
||||||
|
v.append(&mut ip_dest.to_vec());
|
||||||
|
v
|
||||||
|
}
|
||||||
|
pub fn ax_make_resp(&self, ax: Address) -> Result<Ax25Frame> {
|
||||||
|
let sha = &self.sha[..].try_into()?;
|
||||||
|
let ax_dest = Address::from_octets(sha)?;
|
||||||
|
let arp: Vec<u8> = Self::ax25_zip(
|
||||||
|
&ax.octets(),
|
||||||
|
&self.tpa[..].try_into()?,
|
||||||
|
sha,
|
||||||
|
&self.spa[..].try_into()?,
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
let frame_content = FrameContent::UnnumberedInformation(UnnumberedInformation {
|
||||||
|
pid: ProtocolIdentifier::ArpaAddress,
|
||||||
|
info: arp,
|
||||||
|
poll_or_final: false,
|
||||||
|
});
|
||||||
|
Ok(Ax25Frame {
|
||||||
|
source: ax,
|
||||||
|
destination: ax_dest,
|
||||||
|
route: vec![],
|
||||||
|
command_or_response: None,
|
||||||
|
content: frame_content,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn qst_addr() -> Address {
|
||||||
|
let mut addr = Address::default();
|
||||||
|
addr.callsign = "QST".to_string();
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
//fn ax_arp_resp()
|
||||||
|
fn ax_arp(ax_src: Address, ip_src: Ipv4Addr, ip_dest: Ipv4Addr) -> Ax25Frame {
|
||||||
|
let ax_dest = qst_addr();
|
||||||
|
let frame_content = FrameContent::UnnumberedInformation(UnnumberedInformation {
|
||||||
|
pid: ax25::frame::ProtocolIdentifier::ArpaAddress,
|
||||||
|
info: ArpPacket::ax_request_raw(&ax_src, ip_src, ip_dest),
|
||||||
|
poll_or_final: false,
|
||||||
|
});
|
||||||
|
let frame = Ax25Frame {
|
||||||
|
source: ax_src,
|
||||||
|
destination: ax_dest,
|
||||||
|
route: vec![],
|
||||||
|
command_or_response: None,
|
||||||
|
content: frame_content,
|
||||||
|
};
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
fn ax_ip(ax_src: Address, ax_dest: Address, ipdata: Vec<u8>) -> Ax25Frame {
|
||||||
|
let frame_content = FrameContent::UnnumberedInformation(UnnumberedInformation {
|
||||||
|
pid: ProtocolIdentifier::ArpaIp,
|
||||||
|
info: ipdata,
|
||||||
|
poll_or_final: false,
|
||||||
|
});
|
||||||
|
Ax25Frame {
|
||||||
|
source: ax_src,
|
||||||
|
destination: ax_dest,
|
||||||
|
route: vec![],
|
||||||
|
command_or_response: None,
|
||||||
|
content: frame_content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PacketPending {
|
||||||
|
packet: Vec<u8>,
|
||||||
|
ts: Instant,
|
||||||
|
}
|
||||||
|
impl PacketPending {
|
||||||
|
fn new(packet: Vec<u8>) -> PacketPending {
|
||||||
|
PacketPending {
|
||||||
|
packet,
|
||||||
|
ts: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ArpState {
|
||||||
|
Found(Address, Instant),
|
||||||
|
Pending(VecDeque<PacketPending>, Instant),
|
||||||
|
PendingUpdate(Address, Instant),
|
||||||
|
}
|
||||||
|
fn try_print_ip(tx: bool, p: &[u8]) -> Result<()> {
|
||||||
|
let packet = SlicedPacket::from_ip(p)?;
|
||||||
|
if let Some(InternetSlice::Ipv4(h, _)) = packet.ip {
|
||||||
|
print_ip(tx, &h, &packet.transport);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Error not IPv4"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArpTable = Arc<Mutex<HashMap<Ipv4Addr, ArpState>>>;
|
||||||
|
async fn update(
|
||||||
|
this: &ArpTable,
|
||||||
|
ip: &Ipv4Addr,
|
||||||
|
ax: &Address,
|
||||||
|
tnc: &Sender<Ax25Frame>,
|
||||||
|
ax_src: &Address,
|
||||||
|
) -> Result<()> {
|
||||||
|
println!("\t\tARP Updating Table: {} is {}", ip, ax);
|
||||||
|
let now = Instant::now();
|
||||||
|
let mut tbl = this.lock().await;
|
||||||
|
//match tbl.get_mut(&ip) {
|
||||||
|
let old = tbl.insert(ip.clone(), ArpState::Found(ax.clone(), now));
|
||||||
|
drop(tbl);
|
||||||
|
//println!("\t\told: {:?}", old);
|
||||||
|
|
||||||
|
if let Some(ArpState::Pending(pending, _)) = old {
|
||||||
|
//println!("\t\tYES! YES! YES! YES! YES!");
|
||||||
|
for p in pending {
|
||||||
|
//println!("Packet");
|
||||||
|
if p.ts.elapsed() < ARP_PENDING_TTL {
|
||||||
|
// tnc.send_frame(&ax_ip(ax_src.clone(), ax.clone(), p.packet))?;
|
||||||
|
if try_print_ip(true, &p.packet).is_err() {
|
||||||
|
println!("TX Pending Frame");
|
||||||
|
}
|
||||||
|
tnc.send(ax_ip(ax_src.clone(), ax.clone(), p.packet))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn print_ip(tx: bool, ip_h: &Ipv4HeaderSlice, ts_h: &Option<TransportSlice>) {
|
||||||
|
let tx = if tx { "TX" } else { "RX" };
|
||||||
|
let dst_ip = ip_h.destination_addr();
|
||||||
|
let src_ip = ip_h.source_addr();
|
||||||
|
match ts_h {
|
||||||
|
Some(TransportSlice::Tcp(h)) => {
|
||||||
|
let src_prt = h.source_port();
|
||||||
|
let dst_prt = h.destination_port();
|
||||||
|
let o = h.sequence_number();
|
||||||
|
if h.ack() {
|
||||||
|
println!(
|
||||||
|
"{tx} Frame: TCPACK {}:{} -> {}:{} ({o})",
|
||||||
|
src_ip, src_prt, dst_ip, dst_prt
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"{tx} Frame: TCP/IP {}:{} -> {}:{} ({o})",
|
||||||
|
src_ip, src_prt, dst_ip, dst_prt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(TransportSlice::Udp(h)) => {
|
||||||
|
let src_prt = h.source_port();
|
||||||
|
let dst_prt = h.destination_port();
|
||||||
|
println!(
|
||||||
|
"{tx} Frame: UDP/IP {}:{} -> {}:{}",
|
||||||
|
src_ip, src_prt, dst_ip, dst_prt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("{tx} Frame: IP {} -> {}", src_ip, dst_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*fn print_ip(tx: bool, packet: &SlicedPacket) {
|
||||||
|
let tx = if tx { "TX" } else { "RX" };
|
||||||
|
let (dst_ip, src_ip)if let Some(InternetSlice::Ipv4(header, _)) = packet.ip {
|
||||||
|
let dst_ip = header.destination_addr();
|
||||||
|
let src_ip = header.source_addr();
|
||||||
|
match packet.transport {
|
||||||
|
Some(TransportSlice::Tcp(h)) => {
|
||||||
|
let src_prt = h.source_port();
|
||||||
|
let dst_prt = h.destination_port();
|
||||||
|
let o = h.sequence_number();
|
||||||
|
if h.ack() {
|
||||||
|
println!(
|
||||||
|
"RX Frame: TCPACK {}:{} -> {}:{} ({o})",
|
||||||
|
src_ip, src_prt, dst_ip, dst_prt
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"RX Frame: TCP/IP {}:{} -> {}:{} ({o})",
|
||||||
|
src_ip, src_prt, dst_ip, dst_prt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(TransportSlice::Udp(h)) => {
|
||||||
|
let src_prt = h.source_port();
|
||||||
|
let dst_prt = h.destination_port();
|
||||||
|
println!(
|
||||||
|
"RX Frame: UDP/IP {}:{} -> {}:{}",
|
||||||
|
src_ip, src_prt, dst_ip, dst_prt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("RX Frame: IP {} -> {}", src_ip, dst_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/// Thread that accepts incoming IP packets and sends AX.25 packets
|
||||||
|
async fn process_ip(
|
||||||
|
ax_addr: Address,
|
||||||
|
arp_table: Arc<Mutex<HashMap<Ipv4Addr, ArpState>>>,
|
||||||
|
tnc: Sender<Ax25Frame>,
|
||||||
|
mut ip_in_rx: Receiver<Vec<u8>>,
|
||||||
|
ip_addr: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Option<Ipv4Addr>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let allow_multicast = false;
|
||||||
|
let allow_broadcast = false;
|
||||||
|
let local_broadcast = Ipv4Addr::from(ip_addr.mask(&netmask) | !u32::from(netmask));
|
||||||
|
// let local_broadcast = Ipv4Addr::from((u32::from(ip) & u32::from(subnetmask)) | !u32::from(subnetmask));
|
||||||
|
//while let Some(packet) = ip_in_rx.recv().await {
|
||||||
|
loop {
|
||||||
|
let packet = ip_in_rx
|
||||||
|
.recv()
|
||||||
|
.await
|
||||||
|
.ok_or(anyhow!("IP input buffer closed"))?;
|
||||||
|
|
||||||
|
match SlicedPacket::from_ip(&packet) {
|
||||||
|
Err(value) => println!("Err {:?}", value),
|
||||||
|
Ok(value) => {
|
||||||
|
match value.ip {
|
||||||
|
Some(InternetSlice::Ipv4(header, _exts)) => {
|
||||||
|
let packet_dest_ip = header.destination_addr();
|
||||||
|
if packet_dest_ip.is_multicast() {
|
||||||
|
if allow_multicast {
|
||||||
|
let ax_dest = qst_addr();
|
||||||
|
tnc.send(ax_ip(ax_addr.clone(), ax_dest, packet)).await?;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if packet_dest_ip.is_broadcast() || packet_dest_ip == local_broadcast {
|
||||||
|
if allow_broadcast {
|
||||||
|
let ax_dest = qst_addr();
|
||||||
|
tnc.send(ax_ip(ax_addr.clone(), ax_dest, packet)).await?;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let same_subnet = packet_dest_ip.mask(&netmask) == ip_addr.mask(&netmask);
|
||||||
|
let frame_dest_ip = match (same_subnet, gateway) {
|
||||||
|
(true, _) => packet_dest_ip,
|
||||||
|
(false, Some(gateway_ip)) => gateway_ip,
|
||||||
|
(false, None) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let src_ip = header.source_addr();
|
||||||
|
let mut tbl = arp_table.lock().await;
|
||||||
|
match tbl.get_mut(&frame_dest_ip) {
|
||||||
|
Some(state) => {
|
||||||
|
match state {
|
||||||
|
ArpState::Found(dest_ax, _ts) => {
|
||||||
|
let dest_ax = dest_ax.clone();
|
||||||
|
//tnc.send_frame(&ax_ip(ax_addr.clone(), dest_ax.clone(), packet))?;
|
||||||
|
print_ip(true, &header, &value.transport);
|
||||||
|
tnc.send(ax_ip(ax_addr.clone(), dest_ax.clone(), packet))
|
||||||
|
.await?;
|
||||||
|
if _ts.elapsed() > ARP_CACHE_TTL {
|
||||||
|
println!(
|
||||||
|
"TX Frame: ARP Who has {}? Tell {}",
|
||||||
|
frame_dest_ip, src_ip
|
||||||
|
);
|
||||||
|
tnc.send(ax_arp(
|
||||||
|
ax_addr.clone(),
|
||||||
|
src_ip,
|
||||||
|
frame_dest_ip,
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
*state = ArpState::PendingUpdate(
|
||||||
|
dest_ax.clone(),
|
||||||
|
Instant::now(),
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"\tFound {} in table: {} EXPIRED!",
|
||||||
|
frame_dest_ip, dest_ax
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"\tFound {} in table: {}",
|
||||||
|
frame_dest_ip, dest_ax
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArpState::Pending(packets, ts) => {
|
||||||
|
packets.push_back(PacketPending::new(packet));
|
||||||
|
while packets.len() > MAX_BUFFERED_PKTS {
|
||||||
|
packets.pop_front();
|
||||||
|
}
|
||||||
|
if ts.elapsed() > ARP_CACHE_TTL {
|
||||||
|
//tnc.send_frame(&ax_arp(ax_addr.clone(), src_ip, dest_ip))?;
|
||||||
|
println!(
|
||||||
|
"TX Frame: ARP Who has {}? Tell {}",
|
||||||
|
frame_dest_ip, src_ip
|
||||||
|
);
|
||||||
|
tnc.send(ax_arp(
|
||||||
|
ax_addr.clone(),
|
||||||
|
src_ip,
|
||||||
|
frame_dest_ip,
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
println!(
|
||||||
|
"\t{} Not found: pending (sent req)",
|
||||||
|
frame_dest_ip
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("\t{} Not found: pending", frame_dest_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArpState::PendingUpdate(dest_ax, _ts) => {
|
||||||
|
let dest_ax = dest_ax.clone();
|
||||||
|
print_ip(true, &header, &value.transport);
|
||||||
|
tnc.send(ax_ip(ax_addr.clone(), dest_ax.clone(), packet))
|
||||||
|
.await?;
|
||||||
|
if _ts.elapsed() > ARP_CACHE_TTL {
|
||||||
|
println!(
|
||||||
|
"TX Frame: ARP Who has {}? Tell {}",
|
||||||
|
frame_dest_ip, src_ip
|
||||||
|
);
|
||||||
|
tnc.send(ax_arp(
|
||||||
|
ax_addr.clone(),
|
||||||
|
src_ip,
|
||||||
|
frame_dest_ip,
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
*state = ArpState::PendingUpdate(
|
||||||
|
dest_ax.clone(),
|
||||||
|
Instant::now(),
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"\t{} Found: {} pending update (sent req)",
|
||||||
|
frame_dest_ip, dest_ax
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"\t{} Found: {} pending update",
|
||||||
|
frame_dest_ip, dest_ax
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
tbl.insert(
|
||||||
|
frame_dest_ip,
|
||||||
|
ArpState::Pending(
|
||||||
|
VecDeque::from([PacketPending::new(packet)]),
|
||||||
|
Instant::now(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
//tnc.send_frame(&ax_arp(ax_addr.clone(), src_ip, dest_ip.clone()))?;
|
||||||
|
println!(
|
||||||
|
"TX Frame: ARP Who has {}? Tell {}",
|
||||||
|
frame_dest_ip, src_ip
|
||||||
|
);
|
||||||
|
tnc.send(ax_arp(ax_addr.clone(), src_ip, frame_dest_ip.clone()))
|
||||||
|
.await?;
|
||||||
|
println!("\t{} Not found (sent req)", frame_dest_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {} //Silently drop non Ipv4 packets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test() {
|
||||||
|
use std::str::FromStr;
|
||||||
|
assert!(Ipv4Addr::from_str("224.0.0.251").unwrap().is_multicast());
|
||||||
|
assert!(Ipv4Addr::from_str("239.255.255.250")
|
||||||
|
.unwrap()
|
||||||
|
.is_multicast());
|
||||||
|
assert!(Ipv4Addr::from_str("224.0.0.22").unwrap().is_multicast());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AxIpBridge {
|
||||||
|
//addr: Address,
|
||||||
|
//arp_table: Arc<ArpTable>,
|
||||||
|
//tnc: Tnc,
|
||||||
|
ip_in: Sender<Vec<u8>>,
|
||||||
|
ip_out: Receiver<Vec<u8>>,
|
||||||
|
}
|
||||||
|
impl AxIpBridge {
|
||||||
|
pub fn new(
|
||||||
|
ax_addr: Address,
|
||||||
|
tnc: (Receiver<Ax25Frame>, Sender<Ax25Frame>),
|
||||||
|
ip_addr: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Option<Ipv4Addr>,
|
||||||
|
) -> Self {
|
||||||
|
let (ip_in, ip_in_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = mpsc::channel(128);
|
||||||
|
let (ip_out_tx, ip_out) = mpsc::channel(128);
|
||||||
|
let arp_table: Arc<Mutex<HashMap<Ipv4Addr, ArpState>>> =
|
||||||
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
|
let (tnc_rx, tnc_tx) = tnc;
|
||||||
|
|
||||||
|
// Thread that accepts incoming IP packets and sends AX.25 packets
|
||||||
|
tokio::spawn(process_ip(
|
||||||
|
ax_addr.clone(),
|
||||||
|
arp_table.clone(),
|
||||||
|
tnc_tx.clone(),
|
||||||
|
ip_in_rx,
|
||||||
|
ip_addr.clone(),
|
||||||
|
netmask,
|
||||||
|
gateway,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Thread that accepts incoming AX.25 packets and sends IP packets
|
||||||
|
tokio::spawn(process_ax(
|
||||||
|
ax_addr, arp_table, ip_out_tx, ip_addr, tnc_rx, tnc_tx,
|
||||||
|
));
|
||||||
|
|
||||||
|
Self { ip_out, ip_in }
|
||||||
|
}
|
||||||
|
pub fn split(self) -> (Sender<Vec<u8>>, Receiver<Vec<u8>>) {
|
||||||
|
(self.ip_in, self.ip_out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Thread that accepts incoming AX.25 packets and sends IP packets
|
||||||
|
async fn process_ax(
|
||||||
|
ax_addr: Address,
|
||||||
|
arp_table: Arc<Mutex<HashMap<Ipv4Addr, ArpState>>>, //ArpTable,
|
||||||
|
// tnc: Tnc,
|
||||||
|
ip_out_tx: Sender<Vec<u8>>,
|
||||||
|
ip: Ipv4Addr,
|
||||||
|
mut tnc_rx: Receiver<Ax25Frame>,
|
||||||
|
tnc_tx: Sender<Ax25Frame>,
|
||||||
|
) -> Result<()> {
|
||||||
|
//let ax_in = tnc.incoming();
|
||||||
|
|
||||||
|
//while let Ok(frame) = ax_in.recv().unwrap() {
|
||||||
|
loop {
|
||||||
|
//let frame = ax_in.recv()??;
|
||||||
|
let frame = tnc_rx.recv().await.ok_or(anyhow!("Error TNC closed"))?;
|
||||||
|
//println!("Got frame from TNC");
|
||||||
|
if let FrameContent::UnnumberedInformation(content) = frame.content {
|
||||||
|
//println!("Frame is UnnumberedInformation");
|
||||||
|
match content.pid {
|
||||||
|
ProtocolIdentifier::ArpaIp => {
|
||||||
|
// Content is IP packet
|
||||||
|
if let Ok(packet) = SlicedPacket::from_ip(&content.info) {
|
||||||
|
// Drop IPv6 for now
|
||||||
|
if let Some(InternetSlice::Ipv4(header, _)) = packet.ip {
|
||||||
|
print_ip(false, &header, &packet.transport);
|
||||||
|
let dst_ip = header.destination_addr();
|
||||||
|
|
||||||
|
if frame.destination == ax_addr && dst_ip == ip {
|
||||||
|
//TODO CHECK THIS SHIT
|
||||||
|
//TODO don't update table for self (and maybe just drop the packet)
|
||||||
|
//update(&arp_table, &ip, &frame.source, &tnc, &ax_addr)?;
|
||||||
|
update(
|
||||||
|
&arp_table,
|
||||||
|
&header.source_addr(),
|
||||||
|
&frame.source,
|
||||||
|
&tnc_tx,
|
||||||
|
&ax_addr,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
ip_out_tx.send(content.info).await?;
|
||||||
|
} else if let Some(TransportSlice::Icmpv4(h)) = packet.transport {
|
||||||
|
// I don't think this will ever happen with a tun interface
|
||||||
|
// all tun Icmpv4 packets should get caught by the previous if statement
|
||||||
|
println!("{:?}", h.icmp_type());
|
||||||
|
ip_out_tx.send(content.info).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProtocolIdentifier::ArpaAddress => {
|
||||||
|
// Content is ARP packet
|
||||||
|
//if let Ok(packet) = ArpPacket::from_bytes(&content.info) {
|
||||||
|
match ArpPacket::from_bytes(&content.info) {
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error parsing ARP packet: {e}")
|
||||||
|
}
|
||||||
|
Ok(packet) => {
|
||||||
|
//println!("Frame is ARP");
|
||||||
|
if packet.htype != 0x0003
|
||||||
|
|| packet.ptype != 0x00CC
|
||||||
|
|| packet.hlen != 7
|
||||||
|
|| packet.plen != 4
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if packet.oper == 1 {
|
||||||
|
// Request!
|
||||||
|
let target_ip = Ipv4Addr::new(
|
||||||
|
packet.tpa[0],
|
||||||
|
packet.tpa[1],
|
||||||
|
packet.tpa[2],
|
||||||
|
packet.tpa[3],
|
||||||
|
);
|
||||||
|
let sender_ip = Ipv4Addr::new(
|
||||||
|
packet.spa[0],
|
||||||
|
packet.spa[1],
|
||||||
|
packet.spa[2],
|
||||||
|
packet.spa[3],
|
||||||
|
);
|
||||||
|
println!("RX Frame: ARP Who has {}? Tell {}", target_ip, sender_ip);
|
||||||
|
if ip == target_ip {
|
||||||
|
println!("TX Frame: ARP {} is at {}", target_ip, ax_addr);
|
||||||
|
let resp = packet.ax_make_resp(ax_addr.clone())?;
|
||||||
|
tnc_tx.send(resp).await?;
|
||||||
|
}
|
||||||
|
if let Ok(sender_ax) =
|
||||||
|
Address::from_octets(packet.sha[..].try_into()?)
|
||||||
|
{
|
||||||
|
update(&arp_table, &sender_ip, &sender_ax, &tnc_tx, &ax_addr)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
} else if packet.oper == 2 {
|
||||||
|
//response!
|
||||||
|
//update(senderip, sendercall)
|
||||||
|
let sender_ip = Ipv4Addr::new(
|
||||||
|
packet.spa[0],
|
||||||
|
packet.spa[1],
|
||||||
|
packet.spa[2],
|
||||||
|
packet.spa[3],
|
||||||
|
);
|
||||||
|
let target_ip = Ipv4Addr::new(
|
||||||
|
packet.tpa[0],
|
||||||
|
packet.tpa[1],
|
||||||
|
packet.tpa[2],
|
||||||
|
packet.tpa[3],
|
||||||
|
);
|
||||||
|
if let Ok(sender_ax) =
|
||||||
|
Address::from_octets(packet.sha[..].try_into()?)
|
||||||
|
{
|
||||||
|
println!("RX Frame: ARP {} is at {}", sender_ip, sender_ax);
|
||||||
|
update(&arp_table, &sender_ip, &sender_ax, &tnc_tx, &ax_addr)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
println!("RX Frame: ARP Could not decode sender AX Call");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip != target_ip {
|
||||||
|
if let Ok(target_ax) =
|
||||||
|
Address::from_octets(packet.tha[..].try_into()?)
|
||||||
|
{
|
||||||
|
update(
|
||||||
|
&arp_table, &sender_ip, &target_ax, &tnc_tx, &ax_addr,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
// update(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {} // drop frame Silently
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Ok(())
|
||||||
|
}
|
||||||
99
src/kiss_tokio.rs
Normal file
99
src/kiss_tokio.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use ax25::frame::Ax25Frame;
|
||||||
|
use tokio::{
|
||||||
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
|
net::{
|
||||||
|
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
||||||
|
TcpStream, ToSocketAddrs,
|
||||||
|
},
|
||||||
|
sync::mpsc::{self, Receiver, Sender},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Kiss TNC using the Tokio Async runtime
|
||||||
|
pub struct KissTnc {
|
||||||
|
from_tnc: Receiver<Ax25Frame>,
|
||||||
|
to_tnc: Sender<Ax25Frame>,
|
||||||
|
}
|
||||||
|
impl KissTnc {
|
||||||
|
const FEND: u8 = 0xC0;
|
||||||
|
const FESC: u8 = 0xDB;
|
||||||
|
const TFEND: u8 = 0xDC;
|
||||||
|
const TFESC: u8 = 0xDD;
|
||||||
|
pub async fn connect<A: ToSocketAddrs>(addr: A) -> Result<KissTnc> {
|
||||||
|
let socket = TcpStream::connect(addr).await?;
|
||||||
|
let (tcp_rx, tcp_tx) = socket.into_split();
|
||||||
|
|
||||||
|
let (ax_tx, from_tnc) = mpsc::channel(128);
|
||||||
|
let (to_tnc, ax_rx) = mpsc::channel(128);
|
||||||
|
|
||||||
|
tokio::spawn(Self::rx_thread(tcp_rx, ax_tx));
|
||||||
|
tokio::spawn(Self::tx_thread(tcp_tx, ax_rx));
|
||||||
|
|
||||||
|
Ok(KissTnc { from_tnc, to_tnc })
|
||||||
|
}
|
||||||
|
pub fn split(self) -> (Receiver<Ax25Frame>, Sender<Ax25Frame>) {
|
||||||
|
(self.from_tnc, self.to_tnc)
|
||||||
|
}
|
||||||
|
async fn rx_thread(mut tcp_in: OwnedReadHalf, ax_out: Sender<Ax25Frame>) {
|
||||||
|
let mut buf = [0_u8; 2048];
|
||||||
|
let mut frame = vec![];
|
||||||
|
let mut escaped = false;
|
||||||
|
while let Ok(n) = tcp_in.read(&mut buf).await {
|
||||||
|
if n == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for byte in buf[..n].iter() {
|
||||||
|
if escaped {
|
||||||
|
match *byte {
|
||||||
|
0xDC => frame.push(0xC0),
|
||||||
|
0xDD => frame.push(0xDB),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
escaped = false;
|
||||||
|
} else {
|
||||||
|
match *byte {
|
||||||
|
0xDB => escaped = true,
|
||||||
|
0xC0 => {
|
||||||
|
if frame.len() == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Ok(ax) = Ax25Frame::from_bytes(&frame[1..]) {
|
||||||
|
//println!("KISS RX FRAME");
|
||||||
|
if ax_out.send(ax).await.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.clear();
|
||||||
|
}
|
||||||
|
b => frame.push(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn tx_thread(mut tcp_out: OwnedWriteHalf, mut ax_in: Receiver<Ax25Frame>) {
|
||||||
|
while let Some(ax_frame) = ax_in.recv().await {
|
||||||
|
let mut kiss_frame = vec![Self::FEND, 0x00];
|
||||||
|
for byte in ax_frame.to_bytes() {
|
||||||
|
match byte {
|
||||||
|
Self::FEND => {
|
||||||
|
kiss_frame.push(Self::FESC);
|
||||||
|
kiss_frame.push(Self::TFEND);
|
||||||
|
}
|
||||||
|
Self::FESC => {
|
||||||
|
kiss_frame.push(Self::FESC);
|
||||||
|
kiss_frame.push(Self::TFESC);
|
||||||
|
}
|
||||||
|
byte => kiss_frame.push(byte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kiss_frame.push(Self::FEND);
|
||||||
|
if tcp_out.write(&kiss_frame).await.is_err() {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
//println!("KISS TX FRAME");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/main.rs
Normal file
87
src/main.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use futures::{SinkExt, StreamExt};
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use tun::TunPacket;
|
||||||
|
|
||||||
|
use ax25::frame::Address;
|
||||||
|
|
||||||
|
mod arp;
|
||||||
|
mod tools;
|
||||||
|
|
||||||
|
mod kiss_tokio;
|
||||||
|
use kiss_tokio::KissTnc;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Cli {
|
||||||
|
call: String,
|
||||||
|
kiss: String,
|
||||||
|
ip: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Option<Ipv4Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
let ip_addr = cli.ip;
|
||||||
|
let netmask = cli.netmask;
|
||||||
|
let gateway: Option<Ipv4Addr> = cli.gateway;
|
||||||
|
let ax_addr = Address::from_str(&cli.call).unwrap();
|
||||||
|
|
||||||
|
let tnc = KissTnc::connect(&cli.kiss).await?;
|
||||||
|
|
||||||
|
let mut config = tun::Configuration::default();
|
||||||
|
config.address(ip_addr).netmask(netmask).up();
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
config.platform(|config| {
|
||||||
|
config.packet_information(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
let (mut dev_sink, mut dev_source) = tun::create_as_async(&config)?.into_framed().split();
|
||||||
|
|
||||||
|
let arp_bridge = arp::AxIpBridge::new(ax_addr, tnc.split(), ip_addr, netmask, gateway);
|
||||||
|
let (to_bridge, mut from_bridge) = arp_bridge.split();
|
||||||
|
|
||||||
|
// read packets from the bridge and send them to the os tun device
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
match from_bridge.recv().await {
|
||||||
|
Some(pkt) => {
|
||||||
|
//println!("RX PKT");
|
||||||
|
if let Err(e) = dev_sink.send(TunPacket::new(pkt)).await {
|
||||||
|
println!("Got error {e}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Error: Channel Closed!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// read packets from the os using the tun device source
|
||||||
|
loop {
|
||||||
|
match dev_source.next().await {
|
||||||
|
Some(Ok(pkt)) => {
|
||||||
|
//println!("TX PKT");
|
||||||
|
if let Err(e) = to_bridge.send(pkt.get_bytes().to_vec()).await {
|
||||||
|
println!("Got error {e}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Err(e)) => {
|
||||||
|
println!("Got err: {e}");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Error: Stream Closed!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
262
src/tools.rs
Normal file
262
src/tools.rs
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
use anyhow::bail;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
// TODO (maybe) impl trait ToBits for Ipv4Addr then imple trait MAsk for T where T: ToBits
|
||||||
|
// Then throw all of that out when #![feature(ip_bits)] gets out of nightly
|
||||||
|
pub trait Mask {
|
||||||
|
fn mask(self, mask: &Self) -> u32;
|
||||||
|
fn to_bits(self) -> u32;
|
||||||
|
}
|
||||||
|
impl Mask for std::net::Ipv4Addr {
|
||||||
|
fn mask(self, mask: &Self) -> u32 {
|
||||||
|
u32::from_be_bytes(self.octets()) & u32::from_be_bytes(mask.octets())
|
||||||
|
}
|
||||||
|
fn to_bits(self) -> u32 {
|
||||||
|
u32::from_be_bytes(self.octets())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use ax25::frame::Address;
|
||||||
|
pub trait AxAddrOctets {
|
||||||
|
fn octets(&self) -> [u8; 7];
|
||||||
|
fn from_octets(octets: &[u8; 7]) -> anyhow::Result<Address>;
|
||||||
|
}
|
||||||
|
impl AxAddrOctets for Address {
|
||||||
|
fn octets(&self) -> [u8; 7] {
|
||||||
|
let mut octets = [0_u8; 7];
|
||||||
|
let ascii = self.callsign.as_bytes();
|
||||||
|
for i in 0..6 {
|
||||||
|
let byte = match ascii.get(i) {
|
||||||
|
Some(c) => c << 1,
|
||||||
|
None => b' ' << 1,
|
||||||
|
};
|
||||||
|
octets[i] = byte;
|
||||||
|
}
|
||||||
|
octets[6] = self.ssid << 1;
|
||||||
|
octets
|
||||||
|
}
|
||||||
|
fn from_octets(octets: &[u8; 7]) -> anyhow::Result<Self> {
|
||||||
|
let mut addr = Address::default();
|
||||||
|
let ascii = octets[..6].iter().map(|x| x >> 1).collect();
|
||||||
|
addr.callsign = String::from_utf8(ascii)?;
|
||||||
|
addr.ssid = octets[6] >> 1;
|
||||||
|
Ok(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToBeBytes for Address {
|
||||||
|
fn to_be_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut v = vec![];
|
||||||
|
for byte in self.callsign.as_bytes() {
|
||||||
|
v.push(*byte);
|
||||||
|
}
|
||||||
|
v.push(self.ssid);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToBeBytes {
|
||||||
|
fn to_be_bytes(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
impl ToBeBytes for String {
|
||||||
|
fn to_be_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut s = self.clone().into_bytes();
|
||||||
|
let n = s.len() as u32;
|
||||||
|
if n == 0 {
|
||||||
|
return vec![!0, !0, !0, !0]; // Return NULLSTR if empty
|
||||||
|
}
|
||||||
|
let mut v = Vec::<u8>::new();
|
||||||
|
v.append(&mut n.to_be_bytes().to_vec());
|
||||||
|
v.append(&mut s);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToBeBytes for bool {
|
||||||
|
fn to_be_bytes(&self) -> Vec<u8> {
|
||||||
|
vec![if *self { 1 } else { 0 }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait PoppableParser {
|
||||||
|
fn pop_u8(&mut self) -> anyhow::Result<u8>;
|
||||||
|
fn pop_u16(&mut self) -> anyhow::Result<u16>;
|
||||||
|
fn pop_u32(&mut self) -> anyhow::Result<u32>;
|
||||||
|
fn pop_u64(&mut self) -> anyhow::Result<u64>;
|
||||||
|
fn pop_i8(&mut self) -> anyhow::Result<i8>;
|
||||||
|
fn pop_i16(&mut self) -> anyhow::Result<i16>;
|
||||||
|
fn pop_i32(&mut self) -> anyhow::Result<i32>;
|
||||||
|
fn pop_i64(&mut self) -> anyhow::Result<i64>;
|
||||||
|
fn pop_f32(&mut self) -> anyhow::Result<f32>;
|
||||||
|
fn pop_f64(&mut self) -> anyhow::Result<f64>;
|
||||||
|
fn pop_bool(&mut self) -> anyhow::Result<bool>;
|
||||||
|
fn pop_string(&mut self) -> anyhow::Result<String>;
|
||||||
|
fn pop_bytes(&mut self, n_bytes: usize) -> anyhow::Result<Vec<u8>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PoppableParser for &[u8] {
|
||||||
|
fn pop_bytes(&mut self, n_bytes: usize) -> anyhow::Result<Vec<u8>> {
|
||||||
|
if self.len() < n_bytes {
|
||||||
|
anyhow::bail!("Buffer too small to pop {} bytes", n_bytes);
|
||||||
|
}
|
||||||
|
let value = self[..n_bytes].to_vec();
|
||||||
|
//let mut value = vec![0_u8; n_bytes];
|
||||||
|
//value.copy_from_slice(&self[..n_bytes]);
|
||||||
|
*self = &self[n_bytes..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_string(&mut self) -> anyhow::Result<String> {
|
||||||
|
const NULLSTR: u32 = !0;
|
||||||
|
let z = self.len();
|
||||||
|
let size: usize = match self.pop_u32()? {
|
||||||
|
NULLSTR => 0,
|
||||||
|
size => size as usize,
|
||||||
|
};
|
||||||
|
assert_ne!(z, self.len());
|
||||||
|
if self.len() < size {
|
||||||
|
anyhow::bail!("Buffer too small to parse String of length {}!", size);
|
||||||
|
}
|
||||||
|
let value = str::from_utf8(&self[..size])?;
|
||||||
|
// println!("\t\tGot value: string = {}, len = {}\t\tsize: {}", value, size, self.len());
|
||||||
|
*self = &self[size..];
|
||||||
|
Ok(value.to_owned())
|
||||||
|
}
|
||||||
|
fn pop_bool(&mut self) -> anyhow::Result<bool> {
|
||||||
|
match self.pop_u8() {
|
||||||
|
Err(_) => bail!("Buffer too small to parse bool!\t\tsize: {}", self.len()),
|
||||||
|
Ok(i) => {
|
||||||
|
// println!("\t\tGot value: bool = {}\t\tsize: {}", i!=0, self.len());
|
||||||
|
Ok(i != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// const SIZE: usize = 1;
|
||||||
|
// if self.len() < SIZE { anyhow::bail!("Buffer too small to parse bool!"); }
|
||||||
|
// let value = self[0] != 0;
|
||||||
|
// *self = &self[SIZE..];
|
||||||
|
// Ok(value)
|
||||||
|
// Ok(self.pop_u8()? != 0)
|
||||||
|
}
|
||||||
|
fn pop_i8(&mut self) -> anyhow::Result<i8> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<i8>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer to small to parse i8!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = self[0] as i8;
|
||||||
|
// println!("\t\tGot value: i8 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_i16(&mut self) -> anyhow::Result<i16> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<i16>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer to small to parse i16!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = i16::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: i8 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_i32(&mut self) -> anyhow::Result<i32> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<i32>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer to small to parse i32!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = i32::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: i32 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_i64(&mut self) -> anyhow::Result<i64> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<i64>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer to small to parse i32!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = i64::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: i64 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_u32(&mut self) -> anyhow::Result<u32> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<u32>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer too small to parse u32!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = u32::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: u32 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_u64(&mut self) -> anyhow::Result<u64> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<u64>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer too small to parse u64!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = u64::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: u64 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_u8(&mut self) -> anyhow::Result<u8> {
|
||||||
|
const SIZE: usize = 1;
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer too small to parse u8!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = self[0];
|
||||||
|
// println!("\t\tGot value: u8 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_u16(&mut self) -> anyhow::Result<u16> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<u16>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer to small to parse u16!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = u16::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: i8 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_f32(&mut self) -> anyhow::Result<f32> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<f32>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer too small to parse f32!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = f32::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: f32 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
fn pop_f64(&mut self) -> anyhow::Result<f64> {
|
||||||
|
const SIZE: usize = std::mem::size_of::<f64>();
|
||||||
|
if self.len() < SIZE {
|
||||||
|
anyhow::bail!("Buffer too small to parse f64!\t\tsize: {}", self.len());
|
||||||
|
}
|
||||||
|
let value = f64::from_be_bytes(self[..SIZE].try_into()?);
|
||||||
|
// println!("\t\tGot value: f64 = {}\t\tsize: {}", value, self.len());
|
||||||
|
*self = &self[SIZE..];
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_popper() {
|
||||||
|
let mut buf: &[u8] = &[
|
||||||
|
0, //false
|
||||||
|
1, //true
|
||||||
|
0, 0, 0, 6, // 6: u32 be
|
||||||
|
0, 0, 0, 9, // 9: u32 be
|
||||||
|
255, // 255: u8
|
||||||
|
0, 0, 0, 1, 0, 0, 0, 0, // 1<<32: u64
|
||||||
|
];
|
||||||
|
assert_eq!(false, buf.pop_bool().unwrap());
|
||||||
|
assert_eq!(true, buf.pop_bool().unwrap());
|
||||||
|
assert_eq!(6, buf.pop_u32().unwrap());
|
||||||
|
assert_eq!(9, buf.pop_u32().unwrap());
|
||||||
|
assert_eq!(255, buf.pop_u8().unwrap());
|
||||||
|
assert_eq!(1 << 32, buf.pop_u64().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string_serialization() {
|
||||||
|
let og = String::from("Hello World");
|
||||||
|
let by = og.to_be_bytes();
|
||||||
|
let s = by.as_slice().pop_string().unwrap();
|
||||||
|
assert_eq!(og, s);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user