diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..1855535 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[profile.release] +lto = "thin" +strip = true diff --git a/.drone.jsonnet b/.drone.jsonnet new file mode 100644 index 0000000..d6fcd1a --- /dev/null +++ b/.drone.jsonnet @@ -0,0 +1,92 @@ +local executableName = 'fourth'; +local build_image = 'img.kie.rs/jjkiers/rust-cross:rust1.70-zig'; + +local archs = [ + { target: 'aarch64-unknown-linux-musl', short: 'arm64-musl' }, + { target: 'x86_64-pc-windows-gnu', short: 'windows' }, + { target: 'x86_64-unknown-linux-musl', short: 'amd64-musl' }, +]; + +local getStepName(arch) = 'Build for ' + arch.short; + +local builtExecutableName(arch) = executableName + if std.length(std.findSubstr(arch.short, 'windows')) > 0 then '.exe' else ''; +local targetExecutableName(arch) = executableName + '-' + arch.target + if std.length(std.findSubstr(arch.short, 'windows')) > 0 then '.exe' else ''; + +local getVolumeName(arch) = 'target-' + arch.target; +local getLocalVolumes(arch) = [ + { + name: getVolumeName(arch), + temp: {}, + } + for arch in archs +]; + +local add_build_steps() = [ + { + name: getStepName(arch), + image: build_image, + commands: [ + 'echo Hello World from Jsonnet on ' + arch.target + '!', + 'cargo zigbuild --release --target ' + arch.target, + 'cp target/' + arch.target + '/release/' + builtExecutableName(arch) + ' artifacts/' + targetExecutableName(arch), + 'rm -rf target/' + arch.target + '/release/*', + ], + depends_on: ['Prepare'], + volumes: [{ + name: getVolumeName(arch), + path: '/drone/src/target', + }], + } + for arch in archs +]; + +{ + kind: 'pipeline', + type: 'docker', + name: 'default', + platform: { + arch: 'amd64', + }, + steps: + [{ + name: 'Prepare', + image: build_image, + commands: [ + 'mkdir artifacts', + 'echo Using image: ' + build_image, + 'cargo --version', + 'rustc --version', + ], + }] + + add_build_steps() + + [ + { + name: 'Show built artifacts', + image: build_image, + commands: [ + 'ls -lah artifacts', + ], + depends_on: [getStepName(a) for a in archs], + }, + { + name: 'Create release on gitea', + image: 'plugins/gitea-release', + settings: { + api_key: { + from_secret: 'gitea_token', + }, + base_url: 'https://code.kiers.eu', + files: 'artifacts/*', + checksum: 'sha256', + }, + when: { + event: ['tag', 'promote'], + }, + depends_on: ['Show built artifacts'], + }, + ], + + volumes: getLocalVolumes(archs), + + image_pull_secrets: ['docker_private_repo'], +} diff --git a/.github/workflows/publish-binaries.yml b/.github/workflows/publish-binaries.yml deleted file mode 100644 index 2a3fd56..0000000 --- a/.github/workflows/publish-binaries.yml +++ /dev/null @@ -1,39 +0,0 @@ -on: - release: - types: [published] - -name: Publish binaries to release - -jobs: - publish: - name: Publish for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - include: - - os: ubuntu-latest - artifact_name: fourth - asset_name: fourth-linux-amd64 - - os: macos-latest - artifact_name: fourth - asset_name: fourth-macos-amd64 - - os: windows-latest - artifact_name: fourth.exe - asset_name: fourth-windows-amd64.exe - - steps: - - uses: hecrj/setup-rust-action@master - with: - rust-version: stable - - uses: actions/checkout@v2 - - name: Build - run: cargo build --release --locked - - name: Publish - uses: svenstaro/upload-release-action@v1-release - with: - repo_token: ${{ secrets.PUBLISH_TOKEN }} - file: target/release/${{ matrix.artifact_name }} - asset_name: ${{ matrix.asset_name }} - tag: ${{ github.ref }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 05fab7b..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Rust - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Upgrade Rust - run: rustup update - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose diff --git a/.gitignore b/.gitignore index ea8c4bf..59b2d02 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +config.yaml diff --git a/Cargo.lock b/Cargo.lock index 0b2e718..48e7cbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,25 @@ version = 3 [[package]] -name = "aho-corasick" -version = "1.0.1" +name = "addr2line" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -28,6 +43,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -46,12 +76,27 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "cc" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +dependencies = [ + "libc", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "deranged" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" + [[package]] name = "enum_primitive" version = "0.1.1" @@ -75,10 +120,16 @@ dependencies = [ ] [[package]] -name = "form_urlencoded" -version = "1.1.0" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -156,7 +207,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -191,9 +242,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -201,10 +252,16 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "gimli" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "hermit-abi" @@ -217,12 +274,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "humantime" @@ -235,9 +289,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -245,31 +299,31 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -277,9 +331,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" @@ -293,6 +347,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.8" @@ -301,7 +364,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -342,25 +405,25 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.15", + "num-traits 0.2.16", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.2", "libc", ] @@ -373,6 +436,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -385,22 +457,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" @@ -442,9 +514,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -470,9 +542,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -485,9 +557,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -524,18 +596,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.8.3" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", @@ -544,9 +628,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rusticata-macros" @@ -559,47 +649,47 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ "indexmap", "itoa", @@ -634,18 +724,18 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ "libc", - "winapi", + "windows-sys", ] [[package]] @@ -661,9 +751,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -681,10 +771,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" dependencies = [ + "deranged", "itoa", "libc", "num_threads", @@ -701,9 +792,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -739,11 +830,11 @@ dependencies = [ [[package]] name = "tokio" -version = "1.28.2" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -753,7 +844,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -764,7 +855,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -775,9 +866,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -790,15 +881,15 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -842,134 +933,68 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[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.0", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" diff --git a/Cargo.toml b/Cargo.toml index dcbe18f..573eeca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ futures = "0.3" tls-parser = "0.11" url = "2.2.2" time = { version = "0.3.1", features = ["local-offset", "formatting"] } - tokio = { version = "1.0", features = ["full"] } bytes = "1.1" diff --git a/README-EN.md b/README-EN.md deleted file mode 100644 index 338de75..0000000 --- a/README-EN.md +++ /dev/null @@ -1,70 +0,0 @@ -# Fourth - -> Hey, now we are on level 4! - -[![](https://img.shields.io/crates/v/fourth)](https://crates.io/crates/fourth) [![CI](https://img.shields.io/github/workflow/status/kernelerr/fourth/Rust)](https://github.com/KernelErr/fourth/actions/workflows/rust.yml) - -**Under heavy development, version 0.1 may update frequently** - -Fourth is a layer 4 proxy implemented by Rust to listen on specific ports and transfer TCP/KCP data to remote addresses(only TCP) according to configuration. - -## Features - -- Listen on specific port and proxy to local or remote port -- SNI-based rule without terminating TLS connection -- Allow KCP inbound(warning: untested) - -## Installation - -To gain best performance on your computer's architecture, please consider build the source code. First, you may need [Rust tool chain](https://rustup.rs/). - -```bash -$ cd fourth -$ cargo build --release -``` - -Binary file will be generated at `target/release/fourth`, or you can use `cargo install --path .` to install. - -Or you can use Cargo to install Fourth: - -```bash -$ cargo install fourth -``` - -Or you can download binary file form the Release page. - -## Configuration - -Fourth will read yaml format configuration file from `/etc/fourth/config.yaml`, and you can set custom path to environment variable `FOURTH_CONFIG`, here is an minimal viable example: - -```yaml -version: 1 -log: info - -servers: - proxy_server: - listen: - - "127.0.0.1:8081" - default: remote - -upstream: - remote: "tcp://www.remote.example.com:8082" # proxy to remote address -``` - -Built-in two upstreams: ban(terminate connection immediately), echo. For detailed configuration, check [this example](./example-config.yaml). - -## Performance Benchmark - -Tested on 4C2G server: - -Use fourth to proxy to Nginx(QPS of direct connection: ~120000): ~70000 req/s (Command: `wrk -t200 -c1000 -d120s --latency http://proxy-server:8081`) - -Use fourth to proxy to local iperf3: 8Gbps - -## Thanks - -- [tokio_kcp](https://github.com/Matrix-Zhang/tokio_kcp) - -## License - -Fourth is available under terms of Apache-2.0. \ No newline at end of file diff --git a/README-ZH.md b/README-ZH.md new file mode 100644 index 0000000..c2434f2 --- /dev/null +++ b/README-ZH.md @@ -0,0 +1,80 @@ +# Fourth + +> 这一波在第四层。 + +[![](https://img.shields.io/crates/v/fourth)](https://crates.io/crates/fourth) [![CI](https://img.shields.io/github/workflow/status/kernelerr/fourth/Rust)](https://github.com/KernelErr/fourth/actions/workflows/rust.yml) + +[English](/README-EN.md) + +**积极开发中,0.1版本迭代可能较快** + +Fourth是一个Rust实现的Layer 4代理,用于监听指定端口TCP/KCP流量,并根据规则转发到指定目标(目前只支持TCP)。 + +## 功能 + +- 监听指定端口代理到本地或远端指定端口 +- 监听指定端口,通过TLS ClientHello消息中的SNI进行分流 +- 支持KCP入站(警告:未测试) + +## 安装方法 + +为了确保获得您架构下的最佳性能,请考虑自行编译,首选需要确保您拥有[Rust工具链](https://rustup.rs/)。 + +```bash +$ cd fourth +$ cargo build --release +``` + +将在`target/release/fourth`生成二进制文件,您也可以使用`cargo install --path . `来安装二进制文件。 + +或者您也可以使用Cargo直接安装: + +```bash +$ cargo install fourth +``` + +或者您也可以直接从Release中下载二进制文件。 + +## 配置 + +Fourth使用yaml格式的配置文件,默认情况下会读取`/etc/fourth/config.yaml`,您也可以设置自定义路径到环境变量`FOURTH_CONFIG`,如下是一个最小有效配置: + +```yaml +version: 1 +log: info + +servers: + proxy_server: + listen: + - "127.0.0.1:8081" + default: remote + +upstream: + remote: "tcp://www.remote.example.com:8082" # proxy to remote address +``` + +内置两个的upstream:ban(立即中断连接)、echo(返回读到的数据)。更详细的配置可以参考[示例配置](./example-config.yaml)。 + +注意:[::]会默认同时绑定IPv4和IPv6。 + +## 性能测试 + +在4C2G的服务器上测试: + +使用Fourth代理到Nginx(直连QPS 120000): ~70000req/s (测试命令:`wrk -t200 -c1000 -d120s --latency http://proxy-server:8081 `) + +使用Fourth代理到本地iperf3:8Gbps + +## io_uring? + +尽管经过了很多尝试,我们发现目前一些Rust下面的io_uring实现存在问题,我们使用的io_uring库实现尽管在吞吐量上可以做到单线程20Gbps(相比之下Tokio仅有8Gbps),但在QPS上存在性能损失较大的问题。因此在有成熟的io_uring实现之前,我们仍然选择epoll。之后我们会持续关注相关进展。 + +可能以后会为Linux高内核版本的用户提供可选的io_uring加速。 + +## 感谢 + +- [tokio_kcp](https://github.com/Matrix-Zhang/tokio_kcp) + +## 协议 + +Fourth以Apache-2.0协议开源。 diff --git a/README.md b/README.md index c2434f2..338de75 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,41 @@ # Fourth -> 这一波在第四层。 +> Hey, now we are on level 4! [![](https://img.shields.io/crates/v/fourth)](https://crates.io/crates/fourth) [![CI](https://img.shields.io/github/workflow/status/kernelerr/fourth/Rust)](https://github.com/KernelErr/fourth/actions/workflows/rust.yml) -[English](/README-EN.md) +**Under heavy development, version 0.1 may update frequently** -**积极开发中,0.1版本迭代可能较快** +Fourth is a layer 4 proxy implemented by Rust to listen on specific ports and transfer TCP/KCP data to remote addresses(only TCP) according to configuration. -Fourth是一个Rust实现的Layer 4代理,用于监听指定端口TCP/KCP流量,并根据规则转发到指定目标(目前只支持TCP)。 +## Features -## 功能 +- Listen on specific port and proxy to local or remote port +- SNI-based rule without terminating TLS connection +- Allow KCP inbound(warning: untested) -- 监听指定端口代理到本地或远端指定端口 -- 监听指定端口,通过TLS ClientHello消息中的SNI进行分流 -- 支持KCP入站(警告:未测试) +## Installation -## 安装方法 - -为了确保获得您架构下的最佳性能,请考虑自行编译,首选需要确保您拥有[Rust工具链](https://rustup.rs/)。 +To gain best performance on your computer's architecture, please consider build the source code. First, you may need [Rust tool chain](https://rustup.rs/). ```bash $ cd fourth $ cargo build --release ``` -将在`target/release/fourth`生成二进制文件,您也可以使用`cargo install --path . `来安装二进制文件。 +Binary file will be generated at `target/release/fourth`, or you can use `cargo install --path .` to install. -或者您也可以使用Cargo直接安装: +Or you can use Cargo to install Fourth: ```bash $ cargo install fourth ``` -或者您也可以直接从Release中下载二进制文件。 +Or you can download binary file form the Release page. -## 配置 +## Configuration -Fourth使用yaml格式的配置文件,默认情况下会读取`/etc/fourth/config.yaml`,您也可以设置自定义路径到环境变量`FOURTH_CONFIG`,如下是一个最小有效配置: +Fourth will read yaml format configuration file from `/etc/fourth/config.yaml`, and you can set custom path to environment variable `FOURTH_CONFIG`, here is an minimal viable example: ```yaml version: 1 @@ -53,28 +51,20 @@ upstream: remote: "tcp://www.remote.example.com:8082" # proxy to remote address ``` -内置两个的upstream:ban(立即中断连接)、echo(返回读到的数据)。更详细的配置可以参考[示例配置](./example-config.yaml)。 +Built-in two upstreams: ban(terminate connection immediately), echo. For detailed configuration, check [this example](./example-config.yaml). -注意:[::]会默认同时绑定IPv4和IPv6。 +## Performance Benchmark -## 性能测试 +Tested on 4C2G server: -在4C2G的服务器上测试: +Use fourth to proxy to Nginx(QPS of direct connection: ~120000): ~70000 req/s (Command: `wrk -t200 -c1000 -d120s --latency http://proxy-server:8081`) -使用Fourth代理到Nginx(直连QPS 120000): ~70000req/s (测试命令:`wrk -t200 -c1000 -d120s --latency http://proxy-server:8081 `) +Use fourth to proxy to local iperf3: 8Gbps -使用Fourth代理到本地iperf3:8Gbps - -## io_uring? - -尽管经过了很多尝试,我们发现目前一些Rust下面的io_uring实现存在问题,我们使用的io_uring库实现尽管在吞吐量上可以做到单线程20Gbps(相比之下Tokio仅有8Gbps),但在QPS上存在性能损失较大的问题。因此在有成熟的io_uring实现之前,我们仍然选择epoll。之后我们会持续关注相关进展。 - -可能以后会为Linux高内核版本的用户提供可选的io_uring加速。 - -## 感谢 +## Thanks - [tokio_kcp](https://github.com/Matrix-Zhang/tokio_kcp) -## 协议 +## License -Fourth以Apache-2.0协议开源。 +Fourth is available under terms of Apache-2.0. \ No newline at end of file diff --git a/config.yaml.example b/config.yaml.example new file mode 100644 index 0000000..faffa85 --- /dev/null +++ b/config.yaml.example @@ -0,0 +1,16 @@ +version: 1 +log: debug + +servers: + example_server: + listen: + - "0.0.0.0:8443" + tls: true # Enable TLS features like SNI filtering + sni: + api.example.org: example-api + www.example.org: gh-proxy + default: ban + +upstream: + proxy: "tcp://new-www.example.org:443" # Connect over IPv4 or IPv6 to new-www.example.org:443 + example-api: "tcp6://api-v1.example.com:443" # Connect over IPv6 to api-v1.example.com:443 diff --git a/src/config.rs b/src/config.rs index 3fb3252..64c7699 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use crate::servers::upstream_address::UpstreamAddress; use log::{debug, warn}; use serde::Deserialize; use std::collections::{HashMap, HashSet}; @@ -6,8 +7,6 @@ use std::io::{Error as IOError, Read}; use std::net::SocketAddr; use tokio::sync::Mutex; use url::Url; -use tokio::time::Instant; -use time::OffsetDateTime; #[derive(Debug, Clone)] pub struct Config { @@ -47,7 +46,7 @@ pub enum Upstream { } #[derive(Debug)] -struct Addr(Mutex>); +struct Addr(Mutex); impl Default for Addr { fn default() -> Self { @@ -71,38 +70,9 @@ pub struct CustomUpstream { } impl CustomUpstream { - pub async fn resolve_addresses(&self) -> std::io::Result<()> { - { - let addr = self.addresses.0.lock().await; - if addr.len() > 0 { - debug!("Already have addresses: {:?}", &addr); - return Ok(()); - } - } - - debug!("Resolving addresses for {}", &self.addr); - let addresses = tokio::net::lookup_host(self.addr.clone()).await?; - - let mut addr: Vec = match self.protocol.as_ref() { - "tcp4" => addresses.into_iter().filter(|a| a.is_ipv4()).collect(), - "tcp6" => addresses.into_iter().filter(|a| a.is_ipv6()).collect(), - _ => addresses.collect(), - }; - - debug!("Got addresses for {}: {:?}", &self.addr, &addr); - debug!("Resolved at {}", OffsetDateTime::now_utc().format(&time::format_description::well_known::Rfc3339).expect("Format")); - - { - let mut self_addr = self.addresses.0.lock().await; - self_addr.clear(); - self_addr.append(&mut addr); - } - Ok(()) - } - - pub async fn get_addresses(&self) -> Vec { - let a = self.addresses.0.lock().await; - a.clone() + pub async fn resolve_addresses(&self) -> std::io::Result> { + let mut addr = self.addresses.0.lock().await; + addr.resolve((*self.protocol).into()).await } } diff --git a/src/servers/mod.rs b/src/servers/mod.rs index ea54ef8..bda4e79 100644 --- a/src/servers/mod.rs +++ b/src/servers/mod.rs @@ -5,23 +5,25 @@ use std::sync::Arc; use tokio::task::JoinHandle; mod protocol; +pub(crate) mod upstream_address; + use crate::config::{ParsedConfig, Upstream}; use protocol::tcp; #[derive(Debug)] -pub struct Server { +pub(crate) struct Server { pub proxies: Vec>, pub config: ParsedConfig, } #[derive(Debug, Clone)] -pub struct Proxy { +pub(crate) struct Proxy { pub name: String, pub listen: SocketAddr, pub protocol: String, pub tls: bool, pub sni: Option>, - pub default: String, + pub default_action: String, pub upstream: HashMap, } @@ -60,7 +62,7 @@ impl Server { protocol: protocol.clone(), tls, sni: sni.clone(), - default: default.clone(), + default_action: default.clone(), upstream: upstream.clone(), }; new_server.proxies.push(Arc::new(proxy)); diff --git a/src/servers/protocol/tcp.rs b/src/servers/protocol/tcp.rs index c415d29..f33a7f8 100644 --- a/src/servers/protocol/tcp.rs +++ b/src/servers/protocol/tcp.rs @@ -8,7 +8,7 @@ use tokio::io; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use tokio::net::{TcpListener, TcpStream}; -pub async fn proxy(config: Arc) -> Result<(), Box> { +pub(crate) async fn proxy(config: Arc) -> Result<(), Box> { let listener = TcpListener::bind(config.listen).await?; let config = config.clone(); @@ -37,17 +37,17 @@ async fn accept(inbound: TcpStream, proxy: Arc) -> Result<(), Box proxy.default.clone(), + false => proxy.default_action.clone(), true => { let mut hello_buf = [0u8; 1024]; inbound.peek(&mut hello_buf).await?; let snis = get_sni(&hello_buf); if snis.is_empty() { - proxy.default.clone() + proxy.default_action.clone() } else { match proxy.sni.clone() { Some(sni_map) => { - let mut upstream = proxy.default.clone(); + let mut upstream = proxy.default_action.clone(); for sni in snis { let m = sni_map.get(&sni); if m.is_some() { @@ -57,7 +57,7 @@ async fn accept(inbound: TcpStream, proxy: Arc) -> Result<(), Box proxy.default.clone(), + None => proxy.default_action.clone(), } } } @@ -70,18 +70,17 @@ async fn accept(inbound: TcpStream, proxy: Arc) -> Result<(), Box { warn!( "No upstream named {:?} on server {:?}", - proxy.default, proxy.name + proxy.default_action, proxy.name ); - return process(inbound, proxy.upstream.get(&proxy.default).unwrap().clone()).await; + return process( + inbound, + proxy.upstream.get(&proxy.default_action).unwrap().clone(), + ) + .await; // ToDo: Remove unwrap and check default option } }; - match upstream { - Upstream::Custom(u) => u.resolve_addresses().await?, - _ => {} - } - return process(inbound, upstream.clone()).await; } @@ -100,10 +99,9 @@ async fn process( debug!("Bytes read: {:?}", bytes_tx); } Upstream::Custom(custom) => { - custom.resolve_addresses().await?; let outbound = match custom.protocol.as_ref() { "tcp4" | "tcp6" | "tcp" => { - TcpStream::connect(custom.get_addresses().await.as_slice()).await? + TcpStream::connect(custom.resolve_addresses().await?.as_slice()).await? } _ => { error!("Reached unknown protocol: {:?}", custom.protocol); diff --git a/src/servers/upstream_address.rs b/src/servers/upstream_address.rs new file mode 100644 index 0000000..3220a12 --- /dev/null +++ b/src/servers/upstream_address.rs @@ -0,0 +1,115 @@ +use log::debug; +use std::fmt::{Display, Formatter}; +use std::io::Result; +use std::net::SocketAddr; +use time::{Duration, Instant, OffsetDateTime}; + +#[derive(Debug, Clone, Default)] +pub(crate) struct UpstreamAddress { + address: String, + resolved_addresses: Vec, + resolved_time: Option, + ttl: Option, +} + +impl Display for UpstreamAddress { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.address.fmt(f) + } +} + +impl UpstreamAddress { + pub fn is_valid(&self) -> bool { + if let Some(resolved) = self.resolved_time { + if let Some(ttl) = self.ttl { + return resolved.elapsed() < ttl; + } + } + + false + } + + fn is_resolved(&self) -> bool { + self.resolved_addresses.len() > 0 + } + + fn time_remaining(&self) -> Duration { + if !self.is_valid() { + return Duration::seconds(0); + } + + self.ttl.unwrap() - self.resolved_time.unwrap().elapsed() + } + + pub async fn resolve(&mut self, mode: ResolutionMode) -> Result> { + if self.is_resolved() && self.is_valid() { + debug!( + "Already got address {:?}, still valid for {}", + &self.resolved_addresses, + self.time_remaining() + ); + return Ok(self.resolved_addresses.clone()); + } + + debug!("Resolving addresses for {}", &self.address); + + let lookup_result = tokio::net::lookup_host(&self.address).await; + + let resolved_addresses = match lookup_result { + Ok(resolved_addresses) => resolved_addresses, + Err(e) => { + // Protect against DNS flooding. Cache the result for 1 second. + self.resolved_time = Some(Instant::now()); + self.ttl = Some(Duration::seconds(3)); + return Err(e); + } + }; + + let addresses: Vec = match mode { + ResolutionMode::Ipv4 => resolved_addresses + .into_iter() + .filter(|a| a.is_ipv4()) + .collect(), + + ResolutionMode::Ipv6 => resolved_addresses + .into_iter() + .filter(|a| a.is_ipv6()) + .collect(), + + _ => resolved_addresses.collect(), + }; + + debug!("Got addresses for {}: {:?}", &self.address, &addresses); + debug!( + "Resolved at {}", + OffsetDateTime::now_utc() + .format(&time::format_description::well_known::Rfc3339) + .expect("Format") + ); + + self.resolved_addresses = addresses; + self.resolved_time = Some(Instant::now()); + self.ttl = Some(Duration::minutes(1)); + + Ok(self.resolved_addresses.clone()) + } +} + +#[derive(Debug, Default, Clone)] +pub(crate) enum ResolutionMode { + #[default] + Ipv4AndIpv6, + Ipv4, + Ipv6, +} + +impl From<&str> for ResolutionMode { + fn from(value: &str) -> Self { + match value { + "tcp4" => ResolutionMode::Ipv4, + "tcp6" => ResolutionMode::Ipv6, + "tcp" => ResolutionMode::Ipv4AndIpv6, + _ => panic!("This should never happen. Please check configuration parser."), + } + } +}