1use std::io;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
3use std::time::Duration;
4
5pub const NAME: &str = "ripper";
6pub const VERSION: &str = "0.1.0";
7pub const ABOUT: &str = "Rip is a simple client/server to retrieving a public IP via UDP.";
8pub const AUTHOR: &str = "Kevin Cotugno <kevin@kevincotugno.com>";
9
10pub const DEFAULT_PORT: u16 = 44353;
11
12const MAPPED_IPV4_KEY: u16 = 0xFFFF;
13
14pub fn run_client(dest: SocketAddr) -> Result<IpAddr, String> {
15 let socket = match open_socket(dest.is_ipv6(), 0) {
16 Ok(v) => v,
17 Err(err) => return Err(format!("{}", err)),
18 };
19
20 socket
21 .set_read_timeout(Some(Duration::from_secs(10)))
22 .unwrap();
23
24 do_request(dest, &socket)
25}
26
27pub fn run_server(port: u16) -> Result<(), String> {
28 let socket = match open_socket(true, port) {
29 Ok(v) => v,
30 Err(err) => return Err(format!("{}", err)),
31 };
32 eprintln!("Listening on: {:?}", socket);
33
34 let mut unused = [0; 1024];
35 loop {
36 let (_, src) = match socket.recv_from(&mut unused) {
37 Ok(v) => v,
38 Err(err) => return Err(format!("Failed to read message: {}", err)),
39 };
40 eprintln!("Request from: {}", format!("{}", src.ip()));
41
42 let (msg, size) = build_msg(src.ip());
43 let res = socket.send_to(&msg[..size], src);
44 if res.is_err() {
45 eprintln!(
46 "error sending response to {}, with err: ",
47 res.err().unwrap()
48 );
49 }
50 }
51}
52
53pub fn parse_socket_addr(host: &str, port: u16) -> Result<SocketAddr, String> {
54 match parse_ip(host) {
55 Ok(ip) => Ok(SocketAddr::new(ip, port)),
56 Err(v) => Err(v),
57 }
58}
59
60fn open_socket(ipv6: bool, port: u16) -> io::Result<UdpSocket> {
61 UdpSocket::bind(if ipv6 {
62 SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
63 } else {
64 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port)
65 })
66}
67
68fn parse_ip(host: &str) -> Result<IpAddr, String> {
69 match host.parse() {
70 Ok(ip) => Ok(ip),
71 Err(err) => Err(format!(
72 "Unable to parse host: {}, with error: {}",
73 host, err
74 )),
75 }
76}
77
78fn do_request(dest: SocketAddr, socket: &UdpSocket) -> Result<IpAddr, String> {
79 match socket.connect(dest) {
80 Ok(_) => (),
81 Err(err) => return Err(format!("Unable to connect: {}", err)),
82 }
83
84 match socket.send(&[]) {
85 Ok(_) => (),
86 Err(err) => return Err(format!("Failed to send request: {}", err)),
87 }
88
89 let mut buf = [0; 1024];
90 let count = match socket.recv(&mut buf) {
91 Ok(size) => size,
92 Err(error) => return Err(format!("Error reading response: {}", error)),
93 };
94
95 parse_raw_msg(&buf[..count])
96}
97
98fn parse_raw_msg(data: &[u8]) -> Result<IpAddr, String> {
99 if data.is_empty() {
100 return Err(String::from("empty message"));
101 }
102
103 match data[0] {
104 4 => {
105 if data.len() > 4 {
106 Ok(IpAddr::V4(Ipv4Addr::new(
107 data[1], data[2], data[3], data[4],
108 )))
109 } else {
110 println!("{}", data.len());
111 Err(String::from("wrong number of octets for IPv4 address"))
112 }
113 }
114 6 => {
115 if data.len() > 16 {
116 Ok(IpAddr::V6(Ipv6Addr::new(
117 rebuild_seg(data[1], data[2]),
118 rebuild_seg(data[3], data[4]),
119 rebuild_seg(data[5], data[6]),
120 rebuild_seg(data[7], data[8]),
121 rebuild_seg(data[9], data[10]),
122 rebuild_seg(data[11], data[12]),
123 rebuild_seg(data[13], data[14]),
124 rebuild_seg(data[15], data[16]),
125 )))
126 } else {
127 Err(String::from("wrong number of segments for IPv6 address"))
128 }
129 }
130 _ => Err(String::from("invalid IP type")),
131 }
132}
133
134fn rebuild_seg(i: u8, j: u8) -> u16 {
135 let mut x: u16 = u16::from(i);
136 x <<= 8;
137 x |= u16::from(j);
138 x
139}
140
141fn build_msg(ip: IpAddr) -> ([u8; 17], usize) {
142 let mut msg = [0; 17];
143
144 let populate = |octets: &[u8], dest: &mut [u8]| {
145 if octets.len() == 4 {
146 dest[0] = 4;
147 } else {
148 dest[0] = 6;
149 }
150
151 for (i, oct) in octets.iter().enumerate() {
152 dest[i + 1] = *oct;
153 }
154 };
155
156 let size = match ip {
157 IpAddr::V4(v4) => {
158 populate(&v4.octets()[..], &mut msg);
159 5
160 }
161 IpAddr::V6(v6) => {
162 let v4 = v6.to_ipv4();
163
164 if v4.is_some() && v6.segments()[5] == MAPPED_IPV4_KEY {
165 populate(&v4.unwrap().octets()[..], &mut msg);
166 5
167 } else {
168 populate(&v6.octets()[..], &mut msg);
169 17
170 }
171 }
172 };
173
174 (msg, size)
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[test]
182 fn parses_valid_ipv4() -> Result<(), String> {
183 match parse_ip("1.2.3.4") {
184 Ok(v) => ipv4_with_octets(v, 1, 2, 3, 4),
185 Err(error) => Err(String::from(format!("Should be ok, {}", error))),
186 }
187 }
188
189 #[test]
190 fn parses_valid_ipv6() -> Result<(), String> {
191 match parse_ip("2423:33:dfe3::1") {
192 Ok(v) => ipv6_with_segments(v, 0x2423, 0x33, 0xdfe3, 0, 0, 0, 0, 1),
193 Err(error) => Err(String::from(format!("Should be ok, {}", error))),
194 }
195 }
196
197 #[test]
198 fn errors_invalid_ips() -> Result<(), String> {
199 let host = "2423:33:dfe3:invalid::1";
200 match parse_ip(host) {
201 Ok(v) => Err(String::from(format!("Should have returned error, {}", v))),
202 Err(err) => {
203 let expected = format!(
204 "Unable to parse host: {}, with error: invalid IP address syntax",
205 host
206 );
207 if err != expected {
208 Err(String::from(expected))
209 } else {
210 Ok(())
211 }
212 }
213 }
214 }
215
216 fn ipv4_with_octets(ip: IpAddr, a: u8, b: u8, c: u8, d: u8) -> Result<(), String> {
217 match ip {
218 IpAddr::V4(addr) => {
219 if addr.octets() == [a, b, c, d] {
220 Ok(())
221 } else {
222 Err(String::from(format!("octets do not match: {}", addr)))
223 }
224 }
225 IpAddr::V6(_) => Err(String::from("is a ipv6 address")),
226 }
227 }
228
229 fn ipv6_with_segments(
230 ip: IpAddr,
231 a: u16,
232 b: u16,
233 c: u16,
234 d: u16,
235 e: u16,
236 f: u16,
237 g: u16,
238 h: u16,
239 ) -> Result<(), String> {
240 match ip {
241 IpAddr::V4(_) => Err(String::from("is a ipv4 address")),
242 IpAddr::V6(addr) => {
243 if addr.segments() == [a, b, c, d, e, f, g, h] {
244 Ok(())
245 } else {
246 Err(String::from(format!("segments do not match: {}", addr)))
247 }
248 }
249 }
250 }
251}