Inital commit
This commit is contained in:
commit
03e18b00b1
1
.clippy.toml
Normal file
1
.clippy.toml
Normal file
@ -0,0 +1 @@
|
|||||||
|
single-char-binding-names-threshold = 9
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
130
Cargo.lock
generated
Normal file
130
Cargo.lock
generated
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_termios"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rip"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termion"
|
||||||
|
version = "1.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
|
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||||
|
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||||
|
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||||
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
|
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||||
|
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||||
|
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||||
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
|
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
19
Cargo.toml
Normal file
19
Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "rip"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Kevin Cotugno <kevin@kevincotugno.com>"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "rip"
|
||||||
|
path = "src/bin/client.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "rip-server"
|
||||||
|
path = "src/bin/server.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "rip"
|
||||||
|
path = "src/rip/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "~2.32"
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Copyright 2018 Kevin Cotugno
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
51
src/bin/client.rs
Normal file
51
src/bin/client.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
extern crate clap;
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let port = rip::DEFAULT_PORT.to_string();
|
||||||
|
let args = App::new(rip::NAME)
|
||||||
|
.version(rip::VERSION)
|
||||||
|
.author(rip::AUTHOR)
|
||||||
|
.about(rip::ABOUT)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("port")
|
||||||
|
.short("p")
|
||||||
|
.long("port")
|
||||||
|
.help("Set a different port from the default of 44353")
|
||||||
|
.default_value(&port)
|
||||||
|
.takes_value(true),
|
||||||
|
).arg(
|
||||||
|
Arg::with_name("host")
|
||||||
|
.help("Sets the Rip server host")
|
||||||
|
.required(true)
|
||||||
|
.index(1),
|
||||||
|
).get_matches();
|
||||||
|
|
||||||
|
match run(&args) {
|
||||||
|
Ok(ip) => {
|
||||||
|
print!("{}", ip);
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(args: &ArgMatches) -> Result<IpAddr, String> {
|
||||||
|
let port_str = args.value_of("port").unwrap();
|
||||||
|
let port: u16 = match port_str.parse() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => return Err("Port must be a valid unsigned 16bit integer".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dest = match rip::parse_socket_addr(args.value_of("host").unwrap(), port) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
|
rip::run_client(dest)
|
||||||
|
}
|
36
src/bin/server.rs
Normal file
36
src/bin/server.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
extern crate clap;
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
|
||||||
|
const NAME: &str = "rip-server";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let port = rip::DEFAULT_PORT.to_string();
|
||||||
|
let args = App::new(NAME)
|
||||||
|
.version(rip::VERSION)
|
||||||
|
.author(rip::AUTHOR)
|
||||||
|
.about(rip::ABOUT)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("port")
|
||||||
|
.short("p")
|
||||||
|
.long("port")
|
||||||
|
.help("Set a different port from the default of 44353")
|
||||||
|
.default_value(&port)
|
||||||
|
.takes_value(true),
|
||||||
|
).get_matches();
|
||||||
|
|
||||||
|
let result = run(&args);
|
||||||
|
if result.is_err() {
|
||||||
|
println!("{}", result.err().unwrap());
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(args: &ArgMatches) -> Result<(), String> {
|
||||||
|
let port_str = args.value_of("port").unwrap();
|
||||||
|
let port: u16 = match port_str.parse() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => return Err("Port must be a valid unsigned 16bit integer".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
rip::run_server(port)
|
||||||
|
}
|
255
src/rip/lib.rs
Normal file
255
src/rip/lib.rs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub const NAME: &str = "rip";
|
||||||
|
pub const VERSION: &str = "0.1.0";
|
||||||
|
pub const ABOUT: &str = "Rip is a simple client/server to retrieving a public IP via UDP.";
|
||||||
|
pub const AUTHOR: &str = "Kevin Cotugno <kevin@kevincotugno.com>";
|
||||||
|
|
||||||
|
pub const DEFAULT_PORT: u16 = 44353;
|
||||||
|
|
||||||
|
const MAPPED_IPV4_KEY: u16 = 0xFFFF;
|
||||||
|
|
||||||
|
pub fn run_client(dest: SocketAddr) -> Result<IpAddr, String> {
|
||||||
|
let socket = match open_socket(dest.is_ipv6(), 0) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => return Err(format!("{}", err)),
|
||||||
|
};
|
||||||
|
|
||||||
|
socket
|
||||||
|
.set_read_timeout(Some(Duration::from_secs(10)))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
do_request(dest, &socket)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_server(port: u16) -> Result<(), String> {
|
||||||
|
let socket = match open_socket(true, port) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => return Err(format!("{}", err)),
|
||||||
|
};
|
||||||
|
eprintln!("Listening on: {:?}", socket);
|
||||||
|
|
||||||
|
let mut unused = [0; 1024];
|
||||||
|
loop {
|
||||||
|
let (_, src) = match socket.recv_from(&mut unused) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => return Err(format!("Failed to read message: {}", err)),
|
||||||
|
};
|
||||||
|
eprintln!("Request from: {}", format!("{}", src.ip()));
|
||||||
|
|
||||||
|
let (msg, size) = build_msg(src.ip());
|
||||||
|
let res = socket.send_to(&msg[..size], src);
|
||||||
|
if res.is_err() {
|
||||||
|
eprintln!(
|
||||||
|
"error sending response to {}, with err: ",
|
||||||
|
res.err().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_socket_addr(host: &str, port: u16) -> Result<SocketAddr, String> {
|
||||||
|
match parse_ip(host) {
|
||||||
|
Ok(ip) => Ok(SocketAddr::new(ip, port)),
|
||||||
|
Err(v) => Err(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_socket(ipv6: bool, port: u16) -> io::Result<UdpSocket> {
|
||||||
|
UdpSocket::bind(if ipv6 {
|
||||||
|
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||||
|
} else {
|
||||||
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ip(host: &str) -> Result<IpAddr, String> {
|
||||||
|
match host.parse() {
|
||||||
|
Ok(ip) => Ok(ip),
|
||||||
|
Err(err) => Err(format!(
|
||||||
|
"Unable to parse host: {}, with error: {}",
|
||||||
|
host, err
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_request(dest: SocketAddr, socket: &UdpSocket) -> Result<IpAddr, String> {
|
||||||
|
if socket.connect(dest).is_err() {
|
||||||
|
return Err(format!(
|
||||||
|
"Unable to connect: {}",
|
||||||
|
socket.take_error().unwrap().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if socket.send(&[]).is_err() {
|
||||||
|
return Err(format!(
|
||||||
|
"Failed to send request: {}",
|
||||||
|
socket.take_error().unwrap().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
let count = match socket.recv(&mut buf) {
|
||||||
|
Ok(size) => size,
|
||||||
|
Err(error) => return Err(format!("Error reading response: {}", error)),
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_raw_msg(&buf[..count])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_raw_msg(data: &[u8]) -> Result<IpAddr, String> {
|
||||||
|
if data.is_empty() {
|
||||||
|
return Err(String::from("empty message"));
|
||||||
|
}
|
||||||
|
|
||||||
|
match data[0] {
|
||||||
|
4 => {
|
||||||
|
if data.len() > 4 {
|
||||||
|
Ok(IpAddr::V4(Ipv4Addr::new(
|
||||||
|
data[1], data[2], data[3], data[4],
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
println!("{}", data.len());
|
||||||
|
Err(String::from("wrong number of octets for IPv4 address"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
if data.len() > 16 {
|
||||||
|
Ok(IpAddr::V6(Ipv6Addr::new(
|
||||||
|
rebuild_seg(data[1], data[2]),
|
||||||
|
rebuild_seg(data[3], data[4]),
|
||||||
|
rebuild_seg(data[5], data[6]),
|
||||||
|
rebuild_seg(data[7], data[8]),
|
||||||
|
rebuild_seg(data[9], data[10]),
|
||||||
|
rebuild_seg(data[11], data[12]),
|
||||||
|
rebuild_seg(data[13], data[14]),
|
||||||
|
rebuild_seg(data[15], data[16]),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Err(String::from("wrong number of segments for IPv6 address"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(String::from("invalid IP type")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rebuild_seg(i: u8, j: u8) -> u16 {
|
||||||
|
let mut x: u16 = u16::from(i);
|
||||||
|
x <<= 8;
|
||||||
|
x |= u16::from(j);
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_msg(ip: IpAddr) -> ([u8; 17], usize) {
|
||||||
|
let mut msg = [0; 17];
|
||||||
|
|
||||||
|
let populate = |octets: &[u8], dest: &mut [u8]| {
|
||||||
|
if octets.len() == 4 {
|
||||||
|
dest[0] = 4;
|
||||||
|
} else {
|
||||||
|
dest[0] = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, oct) in octets.iter().enumerate() {
|
||||||
|
dest[i + 1] = *oct;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let size = match ip {
|
||||||
|
IpAddr::V4(v4) => {
|
||||||
|
populate(&v4.octets()[..], &mut msg);
|
||||||
|
5
|
||||||
|
}
|
||||||
|
IpAddr::V6(v6) => {
|
||||||
|
let v4 = v6.to_ipv4();
|
||||||
|
|
||||||
|
if v4.is_some() && v6.segments()[5] == MAPPED_IPV4_KEY {
|
||||||
|
populate(&v4.unwrap().octets()[..], &mut msg);
|
||||||
|
5
|
||||||
|
} else {
|
||||||
|
populate(&v6.octets()[..], &mut msg);
|
||||||
|
17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(msg, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_valid_ipv4() -> Result<(), String> {
|
||||||
|
match parse_ip("1.2.3.4") {
|
||||||
|
Ok(v) => ipv4_with_octets(v, 1, 2, 3, 4),
|
||||||
|
Err(error) => Err(String::from(format!("Should be ok, {}", error))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_valid_ipv6() -> Result<(), String> {
|
||||||
|
match parse_ip("2423:33:dfe3::1") {
|
||||||
|
Ok(v) => ipv6_with_segments(v, 0x2423, 0x33, 0xdfe3, 0, 0, 0, 0, 1),
|
||||||
|
Err(error) => Err(String::from(format!("Should be ok, {}", error))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn errors_invalid_ips() -> Result<(), String> {
|
||||||
|
let host = "2423:33:dfe3:invalid::1";
|
||||||
|
match parse_ip(host) {
|
||||||
|
Ok(v) => Err(String::from(format!("Should have returned error, {}", v))),
|
||||||
|
Err(err) => {
|
||||||
|
let expected = format!(
|
||||||
|
"Unable to parse host: {}, with error: invalid IP address syntax",
|
||||||
|
host
|
||||||
|
);
|
||||||
|
if err != expected {
|
||||||
|
Err(String::from(expected))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ipv4_with_octets(ip: IpAddr, a: u8, b: u8, c: u8, d: u8) -> Result<(), String> {
|
||||||
|
match ip {
|
||||||
|
IpAddr::V4(addr) => {
|
||||||
|
if addr.octets() == [a, b, c, d] {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(String::from(format!("octets do not match: {}", addr)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IpAddr::V6(_) => Err(String::from("is a ipv6 address")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ipv6_with_segments(
|
||||||
|
ip: IpAddr,
|
||||||
|
a: u16,
|
||||||
|
b: u16,
|
||||||
|
c: u16,
|
||||||
|
d: u16,
|
||||||
|
e: u16,
|
||||||
|
f: u16,
|
||||||
|
g: u16,
|
||||||
|
h: u16,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match ip {
|
||||||
|
IpAddr::V4(_) => Err(String::from("is a ipv4 address")),
|
||||||
|
IpAddr::V6(addr) => {
|
||||||
|
if addr.segments() == [a, b, c, d, e, f, g, h] {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(String::from(format!("segments do not match: {}", addr)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user