ripper/
lib.rs

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}