You've already forked ipfilter
Initial commit
Includes IPv4 and IPv6 support, and a CLI for generating IpRanges from ip2location DB1 CSV files.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# OS Files
|
||||
*~
|
||||
._*
|
||||
.DS_Store
|
||||
|
||||
# Rust
|
||||
/target
|
||||
@@ -0,0 +1,2 @@
|
||||
hard_tabs = true
|
||||
wrap_comments = true
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"vadimcn.vscode-lldb",
|
||||
"barbosshack.crates-io",
|
||||
"usernamehw.errorlens",
|
||||
"tamasfe.even-better-toml",
|
||||
"rust-lang.rust-analyzer",
|
||||
]
|
||||
}
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
// VSCode
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.tabSize": 4,
|
||||
"files.exclude": {
|
||||
"**/target": true,
|
||||
"**/Cargo.lock": true,
|
||||
},
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.watcherExclude": {
|
||||
"**/.git/**": true,
|
||||
"**/target/**": true,
|
||||
},
|
||||
// Extensions
|
||||
"crates.listPreReleases": true,
|
||||
"evenBetterToml.formatter.alignComments": true,
|
||||
"evenBetterToml.formatter.alignEntries": false,
|
||||
"evenBetterToml.formatter.allowedBlankLines": 1,
|
||||
"evenBetterToml.formatter.arrayAutoExpand": true,
|
||||
"evenBetterToml.formatter.arrayTrailingComma": true,
|
||||
"evenBetterToml.formatter.columnWidth": 80,
|
||||
"evenBetterToml.formatter.reorderKeys": true,
|
||||
"evenBetterToml.formatter.trailingNewline": true,
|
||||
"rust-analyzer.imports.granularity.enforce": true,
|
||||
"rust-analyzer.imports.granularity.group": "module",
|
||||
"rust-analyzer.imports.group.enable": true,
|
||||
"rust-analyzer.imports.merge.glob": false,
|
||||
"rust-analyzer.imports.preferNoStd": true,
|
||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
How to Contribute
|
||||
=================
|
||||
|
||||
We'd love to accept your patches and contributions to this project.
|
||||
We just need you to follow the Contributor License Agreement outlined
|
||||
in the latest v0.0.x of https://github.com/Skrunix/license
|
||||
Generated
+363
@@ -0,0 +1,363 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "ipfilter"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"ipnet",
|
||||
"iprange",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipfilter-cli"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"csv",
|
||||
"ipfilter",
|
||||
"ipnet",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
|
||||
[[package]]
|
||||
name = "iprange"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00"
|
||||
dependencies = [
|
||||
"ipnet",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
[workspace]
|
||||
members = ["cli", "ipfilter"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
authors = ["David Skrundz"]
|
||||
edition = "2024"
|
||||
license-file = "LICENSE.md"
|
||||
rust-version = "1.85.0"
|
||||
|
||||
[workspace.lints.rust]
|
||||
unsafe_code = "forbid"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = "fat"
|
||||
opt-level = 3
|
||||
strip = "debuginfo"
|
||||
|
||||
[workspace.dependencies]
|
||||
ipfilter = { path = "ipfilter", version = "=0.0.0", default-features = false }
|
||||
|
||||
bincode = { version = "2.0.0-rc.3", default-features = false }
|
||||
|
||||
anyhow = { version = "^1", default-features = false }
|
||||
clap = { version = "^4", default-features = false, features = ["std"] }
|
||||
csv = { version = "^1", default-features = false }
|
||||
ipnet = { version = "^2", default-features = false }
|
||||
iprange = { version = "^0.6", default-features = false }
|
||||
itertools = { version = "^0.14", default-features = false }
|
||||
serde = { version = "^1", default-features = false }
|
||||
@@ -0,0 +1,7 @@
|
||||
Skrunix Software License
|
||||
========================
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software is
|
||||
outlined in the latest v0.0.x of https://github.com/Skrunix/license
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS"
|
||||
@@ -0,0 +1,25 @@
|
||||
# IP Filter
|
||||
|
||||
A set of crates for the construction and use of optimized IP filtering mechanisms.
|
||||
|
||||
### Setup
|
||||
|
||||
1. Create `private/secret.sh` containing `export IP2LOCATION_TOKEN=''`
|
||||
1. Run `./private/dl.sh DB1LITECSV DB1LITECSVIPV6`
|
||||
1. List available countries using `cargo run -- -f private/DB1-LITE-V4.CSV list`
|
||||
1. Generate a filter using `cargo run -- -i ./private/DB1-LITE-V4.CSV merge -c BD,BR,CN,HK,IL,IN,IQ,IR,KP,PK,QA,RO,RS,RU,SA,SG,SO,SS,SY,TR,TW,UA,DZ -o ./private/filter4.bin`
|
||||
1. Generate a filter using `cargo run -- -i ./private/DB1-LITE-V6.CSV merge -c BD,BR,CN,HK,IL,IN,IQ,IR,KP,PK,QA,RO,RS,RU,SA,SG,SO,SS,SY,TR,TW,UA,DZ -6 -o ./private/filter6.bin`
|
||||
1. Verify IP ranges using `cargo run -- -i ./private/filter4.bin load` or `cargo run -- -i ./private/filter6.bin load -6`
|
||||
|
||||
###### Round trip checks
|
||||
1. `diff <(cargo run -- -i ./private/DB1-LITE-V4.CSV merge -c BD,BR,CN,HK,IL,IN,IQ,IR,KP,PK,QA,RO,RS,RU,SA,SG,SO,SS,SY,TR,TW,UA,DZ) <(cargo run -- -i ./private/filter4.bin load)`
|
||||
1. `diff <(cargo run -- -i ./private/DB1-LITE-V6.CSV merge -c BD,BR,CN,HK,IL,IN,IQ,IR,KP,PK,QA,RO,RS,RU,SA,SG,SO,SS,SY,TR,TW,UA,DZ -6) <(cargo run -- -i ./private/filter6.bin load -6)`
|
||||
|
||||
## Various builds
|
||||
|
||||
- build: `cargo hack --feature-powerset build`
|
||||
- clippy: `cargo hack --feature-powerset clippy -- -D warnings`
|
||||
- fmt: `cargo fmt --check`
|
||||
- miri: `cargo +nightly hack --feature-powerset miri test`
|
||||
- docs: `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features`
|
||||
- publish: `cargo publish --dry-run -p ipfilter`
|
||||
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "ipfilter-cli"
|
||||
version = "0.0.0"
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license-file.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
ipfilter = { workspace = true, features = ["std"] }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, features = [
|
||||
"derive",
|
||||
"color",
|
||||
"help",
|
||||
"suggestions",
|
||||
"usage",
|
||||
] }
|
||||
csv = { workspace = true }
|
||||
ipnet = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
@@ -0,0 +1,38 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
#[arg(short, long, value_name = "FILE")]
|
||||
pub input: PathBuf,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// Print a list of all countries and their codes
|
||||
List,
|
||||
/// Merge country IP blocks
|
||||
Merge {
|
||||
/// Comma separated list of country codes
|
||||
#[arg(short, long)]
|
||||
countries: String,
|
||||
|
||||
/// IPv6
|
||||
#[arg(short, default_value = "false")]
|
||||
_6: bool,
|
||||
|
||||
#[arg(short, long, value_name = "FILE")]
|
||||
output: Option<PathBuf>,
|
||||
},
|
||||
/// Load a
|
||||
Load {
|
||||
/// IPv6
|
||||
#[arg(short, default_value = "false")]
|
||||
_6: bool,
|
||||
},
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
use core::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
|
||||
use ipfilter::{v4, v6};
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use ipnet::{Ipv4Subnets, Ipv6Subnets};
|
||||
|
||||
mod cli;
|
||||
use cli::{Cli, Commands};
|
||||
use itertools::Itertools;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let input = fs::File::open(cli.input)?;
|
||||
|
||||
match cli.command {
|
||||
Commands::List => {
|
||||
let mut reader = csv::ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.from_reader(input);
|
||||
|
||||
let mut countries = HashSet::<(String, String)>::new();
|
||||
|
||||
for result in reader.records() {
|
||||
let record = result?;
|
||||
countries.insert((record[2].to_owned(), record[3].to_owned()));
|
||||
}
|
||||
|
||||
let mut countries: Vec<_> = countries.drain().collect();
|
||||
countries.sort_by(|lhs, rhs| lhs.0.cmp(&rhs.0));
|
||||
|
||||
for (code, country) in countries {
|
||||
println!("{code} - {country}");
|
||||
}
|
||||
}
|
||||
Commands::Merge {
|
||||
countries,
|
||||
output,
|
||||
_6,
|
||||
} => {
|
||||
let mut reader = csv::ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.from_reader(input);
|
||||
|
||||
let countries: HashSet<String> = countries.split(',').map(ToOwned::to_owned).collect();
|
||||
|
||||
let records = reader
|
||||
.records()
|
||||
.filter_ok(|r| countries.contains(&r[2]))
|
||||
.map(|r| r.map_err(anyhow::Error::from));
|
||||
|
||||
macro_rules! merge_ip {
|
||||
($v:ident, $net:ty, $addr:ty) => {
|
||||
let r = records
|
||||
.map(|r| {
|
||||
r.and_then(|record| {
|
||||
Ok(<$net>::new(
|
||||
<$addr>::from_bits(record[0].parse()?),
|
||||
<$addr>::from_bits(record[1].parse()?),
|
||||
0,
|
||||
))
|
||||
})
|
||||
})
|
||||
.flatten_ok();
|
||||
|
||||
let range = $v::from_fallible_iter(r)?;
|
||||
|
||||
if let Some(o) = output {
|
||||
let mut writer = fs::File::create(o)?;
|
||||
$v::write_to(range, &mut writer)?;
|
||||
} else {
|
||||
for subnet in &range {
|
||||
println!("{subnet}");
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
if _6 {
|
||||
merge_ip!(v6, Ipv6Subnets, Ipv6Addr);
|
||||
} else {
|
||||
merge_ip!(v4, Ipv4Subnets, Ipv4Addr);
|
||||
}
|
||||
}
|
||||
Commands::Load { _6 } => {
|
||||
macro_rules! load_ip {
|
||||
($v:ident, $net:ty, $addr:ty) => {
|
||||
let range = $v::read_from(&mut &input)?;
|
||||
|
||||
for subnet in &range {
|
||||
println!("{subnet}");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if _6 {
|
||||
load_ip!(v6, Ipv6Subnets, Ipv6Addr);
|
||||
} else {
|
||||
load_ip!(v4, Ipv4Subnets, Ipv4Addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "ipfilter"
|
||||
version = "0.0.0"
|
||||
|
||||
description = "A library to streamline IP filtering"
|
||||
repository = "https://github.com/QuantumShade/ipfilter"
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license-file.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
std = ["bincode/std"]
|
||||
|
||||
[dependencies]
|
||||
ipnet = { workspace = true }
|
||||
iprange = { workspace = true, features = ["serde"] }
|
||||
|
||||
bincode = { workspace = true, optional = true, features = ["serde"] }
|
||||
@@ -0,0 +1,67 @@
|
||||
//! A library to streamline IP filtering. Supports creating, serializing, and
|
||||
//! deserializing [Ipv4Range] and [Ipv6Range] for optimized filtering.
|
||||
|
||||
#![forbid(unused_doc_comments)]
|
||||
#![forbid(missing_docs)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
macro_rules! declare_filter {
|
||||
($mod:ident, $net:ident) => {
|
||||
#[doc = concat!("Types and functions for IP", stringify!($mod), " filtering")]
|
||||
pub mod $mod {
|
||||
use ipnet::$net;
|
||||
|
||||
/// The range type for this module
|
||||
pub type IpRange = iprange::IpRange<$net>;
|
||||
|
||||
/// Create a simplified [IpRange] from a fallible [Iterator]
|
||||
pub fn from_fallible_iter<I, E>(iter: I) -> Result<IpRange, E>
|
||||
where
|
||||
I: Iterator<Item = Result<$net, E>>,
|
||||
{
|
||||
let mut range = IpRange::new();
|
||||
|
||||
for subnet in iter {
|
||||
range.add(subnet?);
|
||||
}
|
||||
|
||||
range.simplify();
|
||||
Ok(range)
|
||||
}
|
||||
|
||||
/// Encode the [IpRange] into any type that implements [std::io::Write]
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
pub fn write_to<W: std::io::Write>(
|
||||
range: IpRange,
|
||||
writer: &mut W,
|
||||
) -> Result<usize, bincode::error::EncodeError> {
|
||||
bincode::encode_into_std_write(
|
||||
bincode::serde::Compat(range),
|
||||
writer,
|
||||
bincode::config::standard(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Decode a [IpRange] from any type that implements [std::io::Read]
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
pub fn read_from<R: std::io::Read>(
|
||||
reader: &mut R,
|
||||
) -> Result<IpRange, bincode::error::DecodeError> {
|
||||
bincode::decode_from_std_read::<bincode::serde::Compat<_>, _, R>(
|
||||
reader,
|
||||
bincode::config::standard(),
|
||||
)
|
||||
.map(|x| x.0)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare_filter!(v4, Ipv4Net);
|
||||
pub use v4::IpRange as Ipv4Range;
|
||||
|
||||
declare_filter!(v6, Ipv6Net);
|
||||
pub use v6::IpRange as Ipv6Range;
|
||||
@@ -0,0 +1,5 @@
|
||||
*
|
||||
|
||||
!.gitignore
|
||||
|
||||
!dl.sh
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script takes a list of arguments for each database to download
|
||||
# and extract. Keep in mind that IP2LOCATION has a rate limit.
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# This script requires `secret.sh` to define the following environment variables:
|
||||
# - IP2LOCATION_TOKEN
|
||||
. secret.sh
|
||||
|
||||
BASE_URL="https://www.ip2location.com/download/?token=$IP2LOCATION_TOKEN&file="
|
||||
|
||||
for CODE in "$@"
|
||||
do
|
||||
if [[ $CODE == *IPV6 ]]
|
||||
then
|
||||
DB="${CODE::${#CODE}-4}"
|
||||
ver="V6"
|
||||
else
|
||||
DB="$CODE"
|
||||
ver="V4"
|
||||
fi
|
||||
|
||||
dbx="${DB::${#DB}-7}"
|
||||
ext="${DB:(-3)}"
|
||||
|
||||
curl -L "$BASE_URL$CODE" > tmp.zip
|
||||
unzip -p tmp.zip "*.$ext" > "$dbx-LITE-$ver.$ext"
|
||||
rm tmp.zip
|
||||
done
|
||||
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "stable"
|
||||
Reference in New Issue
Block a user