├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── assets └── rotator.gif └── src ├── main.rs └── rotator ├── mod.rs └── rotator.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "atty" 5 | version = "0.2.14" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 8 | dependencies = [ 9 | "hermit-abi", 10 | "libc", 11 | "winapi", 12 | ] 13 | 14 | [[package]] 15 | name = "autocfg" 16 | version = "1.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 19 | 20 | [[package]] 21 | name = "bitflags" 22 | version = "1.2.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 25 | 26 | [[package]] 27 | name = "cfg-if" 28 | version = "1.0.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 31 | 32 | [[package]] 33 | name = "clap" 34 | version = "3.0.0-beta.2" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" 37 | dependencies = [ 38 | "atty", 39 | "bitflags", 40 | "clap_derive", 41 | "indexmap", 42 | "lazy_static", 43 | "os_str_bytes", 44 | "strsim", 45 | "termcolor", 46 | "textwrap", 47 | "unicode-width", 48 | "vec_map", 49 | ] 50 | 51 | [[package]] 52 | name = "clap_derive" 53 | version = "3.0.0-beta.2" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" 56 | dependencies = [ 57 | "heck", 58 | "proc-macro-error", 59 | "proc-macro2", 60 | "quote", 61 | "syn", 62 | ] 63 | 64 | [[package]] 65 | name = "getrandom" 66 | version = "0.2.2" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 69 | dependencies = [ 70 | "cfg-if", 71 | "libc", 72 | "wasi", 73 | ] 74 | 75 | [[package]] 76 | name = "hashbrown" 77 | version = "0.9.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 80 | 81 | [[package]] 82 | name = "heck" 83 | version = "0.3.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" 86 | dependencies = [ 87 | "unicode-segmentation", 88 | ] 89 | 90 | [[package]] 91 | name = "hermit-abi" 92 | version = "0.1.18" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 95 | dependencies = [ 96 | "libc", 97 | ] 98 | 99 | [[package]] 100 | name = "indexmap" 101 | version = "1.6.1" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" 104 | dependencies = [ 105 | "autocfg", 106 | "hashbrown", 107 | ] 108 | 109 | [[package]] 110 | name = "lazy_static" 111 | version = "1.4.0" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 114 | 115 | [[package]] 116 | name = "libc" 117 | version = "0.2.87" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" 120 | 121 | [[package]] 122 | name = "log" 123 | version = "0.4.14" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 126 | dependencies = [ 127 | "cfg-if", 128 | ] 129 | 130 | [[package]] 131 | name = "os_str_bytes" 132 | version = "2.4.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" 135 | 136 | [[package]] 137 | name = "ppv-lite86" 138 | version = "0.2.10" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 141 | 142 | [[package]] 143 | name = "proc-macro-error" 144 | version = "1.0.4" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 147 | dependencies = [ 148 | "proc-macro-error-attr", 149 | "proc-macro2", 150 | "quote", 151 | "syn", 152 | "version_check", 153 | ] 154 | 155 | [[package]] 156 | name = "proc-macro-error-attr" 157 | version = "1.0.4" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 160 | dependencies = [ 161 | "proc-macro2", 162 | "quote", 163 | "version_check", 164 | ] 165 | 166 | [[package]] 167 | name = "proc-macro2" 168 | version = "1.0.24" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 171 | dependencies = [ 172 | "unicode-xid", 173 | ] 174 | 175 | [[package]] 176 | name = "quote" 177 | version = "1.0.9" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 180 | dependencies = [ 181 | "proc-macro2", 182 | ] 183 | 184 | [[package]] 185 | name = "rand" 186 | version = "0.8.3" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" 189 | dependencies = [ 190 | "libc", 191 | "rand_chacha", 192 | "rand_core", 193 | "rand_hc", 194 | ] 195 | 196 | [[package]] 197 | name = "rand_chacha" 198 | version = "0.3.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" 201 | dependencies = [ 202 | "ppv-lite86", 203 | "rand_core", 204 | ] 205 | 206 | [[package]] 207 | name = "rand_core" 208 | version = "0.6.2" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" 211 | dependencies = [ 212 | "getrandom", 213 | ] 214 | 215 | [[package]] 216 | name = "rand_hc" 217 | version = "0.3.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" 220 | dependencies = [ 221 | "rand_core", 222 | ] 223 | 224 | [[package]] 225 | name = "rotator" 226 | version = "0.1.0" 227 | dependencies = [ 228 | "clap", 229 | "log", 230 | "rand", 231 | ] 232 | 233 | [[package]] 234 | name = "strsim" 235 | version = "0.10.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 238 | 239 | [[package]] 240 | name = "syn" 241 | version = "1.0.61" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" 244 | dependencies = [ 245 | "proc-macro2", 246 | "quote", 247 | "unicode-xid", 248 | ] 249 | 250 | [[package]] 251 | name = "termcolor" 252 | version = "1.1.2" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 255 | dependencies = [ 256 | "winapi-util", 257 | ] 258 | 259 | [[package]] 260 | name = "textwrap" 261 | version = "0.12.1" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" 264 | dependencies = [ 265 | "unicode-width", 266 | ] 267 | 268 | [[package]] 269 | name = "unicode-segmentation" 270 | version = "1.7.1" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" 273 | 274 | [[package]] 275 | name = "unicode-width" 276 | version = "0.1.8" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 279 | 280 | [[package]] 281 | name = "unicode-xid" 282 | version = "0.2.1" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 285 | 286 | [[package]] 287 | name = "vec_map" 288 | version = "0.8.2" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 291 | 292 | [[package]] 293 | name = "version_check" 294 | version = "0.9.2" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 297 | 298 | [[package]] 299 | name = "wasi" 300 | version = "0.10.2+wasi-snapshot-preview1" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 303 | 304 | [[package]] 305 | name = "winapi" 306 | version = "0.3.9" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 309 | dependencies = [ 310 | "winapi-i686-pc-windows-gnu", 311 | "winapi-x86_64-pc-windows-gnu", 312 | ] 313 | 314 | [[package]] 315 | name = "winapi-i686-pc-windows-gnu" 316 | version = "0.4.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 319 | 320 | [[package]] 321 | name = "winapi-util" 322 | version = "0.1.5" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 325 | dependencies = [ 326 | "winapi", 327 | ] 328 | 329 | [[package]] 330 | name = "winapi-x86_64-pc-windows-gnu" 331 | version = "0.4.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 334 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["root"] 3 | edition = "2018" 4 | name = "rotator" 5 | version = "0.1.0" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | clap = "3.0.0-beta.2" 11 | log = "0.4.14" 12 | rand = "0.8.3" 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Yagiz Degirmenci 4 | 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

rotator

5 | 6 | Rotate over /32 - /48 - /64 CIDR block of IPv6 addresses by randomly generating them. 7 | 8 | ![Should be gif here](assets/rotator.gif) 9 | 10 | 11 |
12 | 13 | 14 | --- 15 | 16 | 17 | 18 | ## Examples 19 | 20 | ```bash 21 | $ rotator -h 22 | ``` 23 | --- 24 | 25 | 26 | ```s 27 | rotator 0.1 28 | 29 | USAGE: 30 | rotator [OPTIONS] --interface --network
31 | 32 | FLAGS: 33 | -h, --help Prints help information 34 | -V, --version Prints version information 35 | 36 | OPTIONS: 37 | -b, --block block range to rotate (Example: 32, 48, 64) [default: 64] 38 | -c, --count Number of the addresses to be routed [default: 5] 39 | -i, --interface Set a network device interface (Example: eth0, ens33) 40 | -n, --network
Address prefix to rotate over. (Example: 2001:db8:0000:0000) 41 | -s, --sleep Rotate to a new IP in x seconds [default: 10] 42 | ``` 43 | 44 | --- 45 | 46 | ## Installation 47 | 48 | Build from the source 49 | 50 | 51 | rotator is written in [Rust](https://www.rust-lang.org). 52 | You will need rustc version [1.45.0](https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html) or higher. 53 | The recommended way to install Rust for development is from the [official download page](https://www.rust-lang.org/tools/install), using rustup. 54 | 55 | To build, download the source code and run: 56 | 57 | ``` 58 | $ cargo build 59 | ``` 60 | 61 | --- 62 | 63 | ## Licence 64 | 65 | rotator's source code is licenced under the [MIT License](https://www.mit.edu/~amini/LICENSE.md). 66 | -------------------------------------------------------------------------------- /assets/rotator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ycd/ipv6-rotator/d51f72b80381c7fa0903f5a238d1ac1454619a0e/assets/rotator.gif -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod rotator; 2 | 3 | use std::process::exit; 4 | 5 | use clap::{App, Arg}; 6 | use rotator::rotator::Rotator; 7 | 8 | fn main() { 9 | // Set level filter to minimum to log everything. 10 | log::set_max_level(log::LevelFilter::Debug); 11 | 12 | let matches = App::new("rotator") 13 | .version("0.1") 14 | .author("Yagiz Degirmenci. ") 15 | .about("Rotate IPv6 addresses") 16 | .arg( 17 | Arg::new("interface") 18 | .short('i') 19 | .long("interface") 20 | .value_name("INTERFACE") 21 | .about("Set a network device interface (Example: eth0, ens33)") 22 | .required(true) 23 | .takes_value(true), 24 | ) 25 | .arg( 26 | Arg::new("network") 27 | .short('n') 28 | .long("network") 29 | .value_name("ADDRESS") 30 | .about("Address prefix to rotate over. (Example: 2001:db8:0000:0000)") 31 | .required(true) 32 | .takes_value(true), 33 | ) 34 | .arg( 35 | Arg::new("count") 36 | .short('c') 37 | .long("count") 38 | .value_name("COUNT") 39 | .about("Number of the addresses to be routed") 40 | .default_value("5") 41 | .takes_value(true), 42 | ) 43 | .arg( 44 | Arg::new("block") 45 | .short('b') 46 | .long("block") 47 | .value_name("CIDR block") 48 | .about("block range to rotate (Example: 32, 48, 64)") 49 | .default_value("64") 50 | .takes_value(true), 51 | ) 52 | .arg( 53 | Arg::new("sleep") 54 | .short('s') 55 | .long("sleep") 56 | .about("Rotate to a new IP in x seconds") 57 | .takes_value(true) 58 | .default_value("10"), 59 | ) 60 | .get_matches(); 61 | 62 | // interface is a device actually, used as device "internally". 63 | let device = matches.value_of("interface").unwrap(); 64 | let sleep = matches 65 | .value_of("sleep") 66 | .unwrap() 67 | .parse::() 68 | .expect("time is not a valid integer"); 69 | let count = matches 70 | .value_of("count") 71 | .unwrap() 72 | .parse::() 73 | .expect("count is not a valid integer"); 74 | let block = match matches.value_of("block").unwrap().parse::() { 75 | Ok(b) => match b { 76 | 32 => rotator::rotator::IpBlock::CIDR32, 77 | 48 => rotator::rotator::IpBlock::CIDR48, 78 | 64 => rotator::rotator::IpBlock::CIDR64, 79 | _ => { 80 | eprintln!("[ERROR] {} is an invalid CIDR block", b); 81 | exit(1) 82 | } 83 | }, 84 | Err(why) => panic!("invalid CIDR block: {:?}", why), 85 | }; 86 | let network = matches.value_of("network").unwrap(); 87 | 88 | let mut rotator = Rotator::builder() 89 | .device(device) 90 | .network(network) 91 | .count(count) 92 | .block(block) 93 | .sleep_time(sleep) 94 | .build(); 95 | 96 | &rotator.rotate(); 97 | } 98 | -------------------------------------------------------------------------------- /src/rotator/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod rotator; 2 | -------------------------------------------------------------------------------- /src/rotator/rotator.rs: -------------------------------------------------------------------------------- 1 | use std::{io::Stderr, process::exit, thread::sleep}; 2 | 3 | use rand::prelude::SliceRandom; 4 | 5 | #[derive(Debug, Clone, Copy, PartialEq)] 6 | pub enum IpBlock { 7 | CIDR32, 8 | CIDR48, 9 | CIDR64, 10 | } 11 | 12 | #[derive(Debug, PartialEq)] 13 | pub struct Rotator<'a> { 14 | pub device: &'a str, 15 | pub sleep_time: u16, 16 | pub block: IpBlock, 17 | pub network: &'a str, 18 | pub count: u16, 19 | addresses: Box>, 20 | available_chars: Vec, 21 | } 22 | 23 | impl<'a> Rotator<'a> { 24 | pub fn builder() -> Self { 25 | Self { 26 | device: "", 27 | sleep_time: 10, 28 | block: IpBlock::CIDR64, 29 | network: "", 30 | count: 5, 31 | addresses: Box::new(Vec::new()), 32 | available_chars: vec![ 33 | "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "e", "f", 34 | ] 35 | .iter() 36 | .map(|s| s.to_string()) 37 | .collect(), 38 | } 39 | } 40 | 41 | // Set the ip block 42 | pub fn block(&mut self, block: IpBlock) -> &mut Self { 43 | self.block = block; 44 | self 45 | } 46 | 47 | pub fn network(&mut self, network: &'a str) -> &mut Self { 48 | self.network = network; 49 | self 50 | } 51 | 52 | pub fn sleep_time(&mut self, sleep_time: u16) -> &mut Self { 53 | self.sleep_time = sleep_time; 54 | self 55 | } 56 | 57 | pub fn device(&mut self, device: &'a str) -> &mut Self { 58 | self.device = device; 59 | self 60 | } 61 | 62 | pub fn count(&mut self, count: u16) -> &mut Self { 63 | self.count = count; 64 | self 65 | } 66 | 67 | pub fn build(&mut self) -> Self { 68 | Self { 69 | block: self.block, 70 | count: self.count, 71 | device: self.device, 72 | network: self.network, 73 | sleep_time: self.sleep_time, 74 | addresses: Box::new(self.addresses.to_vec()), 75 | available_chars: vec![ 76 | "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "e", "f", 77 | ] 78 | .iter() 79 | .map(|s| s.to_string()) 80 | .collect(), 81 | } 82 | } 83 | } 84 | 85 | impl Rotator<'_> { 86 | pub fn rotate(&mut self) { 87 | loop { 88 | for _ in 0..self.count { 89 | self.add_ip().unwrap(); 90 | } 91 | 92 | sleep(std::time::Duration::from_secs(self.sleep_time as u64)); 93 | self.cleanup_addresses().unwrap(); 94 | } 95 | } 96 | 97 | pub fn generate_ip(&mut self) -> String { 98 | match self.block { 99 | IpBlock::CIDR32 => format!( 100 | "{}:{}:{}:{}:{}:{}:{}/{}", 101 | &self.network, 102 | self.gen(), 103 | self.gen(), 104 | self.gen(), 105 | self.gen(), 106 | self.gen(), 107 | self.gen(), 108 | "32" 109 | ), 110 | IpBlock::CIDR48 => format!( 111 | "{}:{}:{}:{}:{}:{}/{}", 112 | &self.network, 113 | self.gen(), 114 | self.gen(), 115 | self.gen(), 116 | self.gen(), 117 | self.gen(), 118 | "48" 119 | ), 120 | IpBlock::CIDR64 => format!( 121 | "{}:{}:{}:{}:{}/{}", 122 | &self.network, 123 | self.gen(), 124 | self.gen(), 125 | self.gen(), 126 | self.gen(), 127 | "64" 128 | ), 129 | } 130 | } 131 | 132 | fn gen(&self) -> String { 133 | vec![ 134 | self.available_chars 135 | .choose(&mut rand::thread_rng()) 136 | .unwrap(), 137 | self.available_chars 138 | .choose(&mut rand::thread_rng()) 139 | .unwrap(), 140 | self.available_chars 141 | .choose(&mut rand::thread_rng()) 142 | .unwrap(), 143 | self.available_chars 144 | .choose(&mut rand::thread_rng()) 145 | .unwrap(), 146 | ] 147 | .iter() 148 | .flat_map(|s| s.chars()) 149 | .collect() 150 | } 151 | 152 | pub fn add_ip(&mut self) -> Result<(), Stderr> { 153 | let new_ip = self.generate_ip(); 154 | self.addresses.push(new_ip.clone()); 155 | 156 | let _ = match std::process::Command::new("ip") 157 | .arg("-6") 158 | .arg("addr") 159 | .arg("add") 160 | .arg(&new_ip) 161 | .arg("dev") 162 | .arg(&self.device) 163 | .output() 164 | { 165 | Ok(_) => println!("[ADD] {}", &new_ip), 166 | Err(why) => { 167 | println!("[ERROR] unable to add new ip addr: {}", why); 168 | exit(1) 169 | } 170 | }; 171 | 172 | Ok(()) 173 | } 174 | 175 | /// Delete all the addresses that is inside addresses 176 | pub fn cleanup_addresses(&mut self) -> Result<(), Stderr> { 177 | self.addresses.iter().for_each(|addr| { 178 | match std::process::Command::new("ip") 179 | .arg("-6") 180 | .arg("addr") 181 | .arg("del") 182 | .arg(addr) 183 | .arg("dev") 184 | .arg(&self.device) 185 | .output() 186 | { 187 | Ok(_) => { 188 | println!("[DEL] {}", &addr); 189 | } 190 | Err(why) => { 191 | eprintln!("[ERROR] unable to delete ip addr({}): {}", &addr, why); 192 | exit(1) 193 | } 194 | } 195 | }); 196 | 197 | self.addresses.clear(); 198 | Ok(()) 199 | } 200 | } 201 | 202 | #[cfg(test)] 203 | mod tests { 204 | use super::*; 205 | 206 | #[test] 207 | fn builder_success_test() { 208 | let rotator = self::Rotator::builder() 209 | .device("eth0") 210 | .network("2001:db8:0000:0000") 211 | .count(5) 212 | .block(IpBlock::CIDR48) 213 | .sleep_time(15) 214 | .build(); 215 | 216 | assert_eq!( 217 | self::Rotator { 218 | device: "eth0", 219 | network: "2001:db8:0000:0000", 220 | count: 5, 221 | block: IpBlock::CIDR48, 222 | sleep_time: 15, 223 | addresses: Box::new(Vec::new()), 224 | available_chars: vec![ 225 | "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "e", "f", 226 | ] 227 | .iter() 228 | .map(|s| s.to_string()) 229 | .collect() 230 | }, 231 | rotator 232 | ); 233 | } 234 | 235 | #[test] 236 | fn test_unique_ip() {} 237 | } 238 | --------------------------------------------------------------------------------