scan_rules/scanner/std/
net.rs

1/*
2Copyright ⓒ 2016 Daniel Keep.
3
4Licensed under the MIT license (see LICENSE or <http://opensource.org
5/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
6<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
7files in the project carrying such notice may not be copied, modified,
8or distributed except according to those terms.
9*/
10/*!
11Scanner implementations for `std::net::*`.
12*/
13use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
14use itertools::Itertools;
15#[cfg(test)] use ::scanner::ScanFromStr;
16
17parse_scanner! { impl<'a> for Ipv4Addr, matcher match_ipv4, matcher err "expected IPv4 address", err map ScanError::other }
18parse_scanner! { impl<'a> for Ipv6Addr, matcher match_ipv6, matcher err "expected IPv6 address", err map ScanError::other }
19parse_scanner! { impl<'a> for SocketAddr, matcher match_sock_addr, matcher err "expected socket address", err map ScanError::other }
20
21fn match_ipv4(s: &str) -> Option<((usize, usize), usize)> {
22    let ibs = &mut s.bytes().enumerate();
23    try_opt!(eat_dec_digs(ibs));
24    if !matches!(ibs.next(), Some((_, b'.'))) { return None; }
25    try_opt!(eat_dec_digs(ibs));
26    if !matches!(ibs.next(), Some((_, b'.'))) { return None; }
27    try_opt!(eat_dec_digs(ibs));
28    if !matches!(ibs.next(), Some((_, b'.'))) { return None; }
29    eat_dec_digs(ibs)
30}
31
32fn match_ipv6(s: &str) -> Option<((usize, usize), usize)> {
33    /*
34        digraph ipv6 {
35            START;
36            Ok;
37            Err;
38        
39            START -> 1 [label="\\x+"];
40            START -> Err [label="*"];
41            START -> "::" [label="::"];
42            
43            1 -> "1+" [label=":\\x+"];
44            1 -> Err [label="*"];
45        
46            "1+" -> "1+" [label=":\\x+"];
47            "1+" -> "::" [label="::"];
48            "1+" -> Ok [label=":\\d+.\\d+.\\d+.\\d+"];
49            "1+" -> Ok [label="*"];
50        
51            "::" -> "::+" [label="\\x+"];
52            "::" -> Ok [label="\\d+.\\d+.\\d+.\\d+"];
53            "::" -> Ok [label="*"];
54        
55            "::+" -> "::+" [label=":\\x+"];
56            "::+" -> Ok [label=":\\d+.\\d+.\\d+.\\d+"];
57            "::+" -> Ok [label="*"];
58        }
59    */
60    fn eat_hex<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
61        let reset = ibs.clone();
62        ibs.take_while_ref(|&(_, b)|
63                matches!(b, b'0'...b'9' | b'a'...b'f' | b'A'...b'F'))
64            .last()
65            .map(|(i, _)| i + 1)
66            .map(|n| ((0, n), n))
67            .or_else(|| { *ibs = reset; None })
68    }
69
70    fn eat_dec<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
71        let reset = ibs.clone();
72        ibs.take_while_ref(|&(_, b)|
73                matches!(b, b'0'...b'9'))
74            .last()
75            .map(|(i, _)| i + 1)
76            .map(|n| ((0, n), n))
77            .or_else(|| { *ibs = reset; None })
78    }
79
80    fn eat_colon_hex<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
81        let reset = ibs.clone();
82        (|| {
83            if !matches!(ibs.next(), Some((_, b':'))) { return None; }
84            eat_hex(ibs)
85        })().or_else(|| { *ibs = reset; None })
86    }
87
88    fn eat_dbl_colon<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
89        let reset = ibs.clone();
90        (|| {
91            if !matches!(ibs.next(), Some((_, b':'))) { return None; }
92            match ibs.next() {
93                Some((i, b':')) => Some(((0, i + 1), i + 1)),
94                _ => None,
95            }
96        })().or_else(|| { *ibs = reset; None })
97    }
98
99    fn eat_ipv4<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
100        let reset = ibs.clone();
101        (|| {
102            let _ = try_opt!(eat_dec(ibs));
103            if !matches!(ibs.next(), Some((_, b'.'))) { return None; }
104            let _ = try_opt!(eat_dec(ibs));
105            if !matches!(ibs.next(), Some((_, b'.'))) { return None; }
106            let _ = try_opt!(eat_dec(ibs));
107            if !matches!(ibs.next(), Some((_, b'.'))) { return None; }
108            eat_dec(ibs)
109        })().or_else(|| { *ibs = reset; None })
110    }
111
112    fn eat_colon_ipv4<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
113        let reset = ibs.clone();
114        (|| {
115            if !matches!(ibs.next(), Some((_, b':'))) { return None; }
116            eat_ipv4(ibs)
117        })().or_else(|| { *ibs = reset; None })
118    }
119
120    fn start<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
121        if let Some(_) = eat_hex(ibs) {
122            one(ibs)
123        } else if let Some(end) = eat_dbl_colon(ibs) {
124            dbl_colon(ibs, end)
125        } else {
126            None
127        }
128    }
129
130    fn one<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
131        if let Some(end) = eat_colon_hex(ibs) {
132            one_plus(ibs, end)
133        } else {
134            None
135        }
136    }
137
138    fn one_plus<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I, mut end: ((usize, usize), usize)) -> Option<((usize, usize), usize)> {
139        loop {
140            if let Some(end) = eat_colon_ipv4(ibs) {
141                return Some(end);
142            } else if let Some(end) = eat_dbl_colon(ibs) {
143                return dbl_colon(ibs, end);
144            } else if let Some(new_end) = eat_colon_hex(ibs) {
145                end = new_end;
146                continue;
147            } else {
148                return Some(end);
149            }
150        }
151    }
152
153    fn dbl_colon<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I, end: ((usize, usize), usize)) -> Option<((usize, usize), usize)> {
154        if let Some(end) = eat_ipv4(ibs) {
155            Some(end)
156        } else if let Some(end) = eat_hex(ibs) {
157            dbl_colon_plus(ibs, end)
158        } else {
159            Some(end)
160        }
161    }
162
163    fn dbl_colon_plus<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I, mut end: ((usize, usize), usize)) -> Option<((usize, usize), usize)> {
164        loop {
165            if let Some(end) = eat_colon_ipv4(ibs) {
166                return Some(end);
167            } else if let Some(new_end) = eat_colon_hex(ibs) {
168                end = new_end;
169                continue;
170            } else {
171                return Some(end);
172            }
173        }
174    }
175
176    let mut ibs = s.bytes().enumerate();
177    match start(&mut ibs) {
178        res => {
179            res
180        }
181    }
182}
183
184fn match_sock_addr(s: &str) -> Option<((usize, usize), usize)> {
185    match_ipv4_sock(s)
186        .or_else(|| match_ipv6_sock(s))
187}
188
189fn match_ipv4_sock(s: &str) -> Option<((usize, usize), usize)> {
190    let ((_, _), off) = try_opt!(match_ipv4(s));
191    let mut ibs = s[off..].bytes().enumerate();
192    if !matches!(ibs.next(), Some((_, b':'))) { return None; }
193    eat_dec_digs(&mut ibs)
194        .map(|((_, b), c)| ((0, b + off), c + off))
195}
196
197fn match_ipv6_sock(s: &str) -> Option<((usize, usize), usize)> {
198    if !s.starts_with("[") { return None; }
199    let ((_, _), off) = try_opt!(match_ipv6(&s[1..]));
200    let off = off + 1;
201    let mut ibs = s[off..].bytes().enumerate();
202    if !matches!(ibs.next(), Some((_, b']'))) { return None; }
203    if !matches!(ibs.next(), Some((_, b':'))) { return None; }
204    eat_dec_digs(&mut ibs)
205        .map(|((_, b), c)| ((0, b + off), c + off))
206}
207
208fn eat_dec_digs<I: Clone + Iterator<Item=(usize, u8)>>(ibs: &mut I) -> Option<((usize, usize), usize)> {
209    ibs.take_while_ref(|&(_, b)| matches!(b, b'0'...b'9'))
210        .last()
211        .map(|(i, _)| i + 1)
212        .map(|n| ((0, n), n))
213}
214
215#[cfg(test)]
216#[test]
217fn test_scan_ipv4addr() {
218    use ::ScanError as SE;
219    use ::ScanErrorKind as SEK;
220
221    macro_rules! check_ipv4 {
222        ($s:expr) => {
223            assert_match!(
224                <Ipv4Addr>::scan_from($s),
225                Ok((v, n)) if v == $s.parse().unwrap() && n == $s.len()
226            )
227        };
228
229        ($s:expr; Ok($v:expr)) => {
230            assert_match!(
231                <Ipv4Addr>::scan_from($s),
232                Ok((v, n)) if v == $v.parse().unwrap() && n == $v.len()
233            )
234        };
235
236        ($s:expr; Err($err:pat)) => {
237            assert_match!(
238                <Ipv4Addr>::scan_from($s),
239                Err($err)
240            )
241        };
242    }
243
244    check_ipv4!("0.0.0.0");
245    check_ipv4!("127.0.0.1");
246    check_ipv4!("255.255.255.255");
247
248    check_ipv4!("256.0.0.1"; Err(SE { kind: SEK::Other(_), .. }));
249    check_ipv4!("255.0.0"; Err(SE { kind: SEK::Syntax(_), .. }));
250    check_ipv4!("255.0.0.1.2"; Ok("255.0.0.1"));
251    check_ipv4!("255.0..1"; Err(SE { kind: SEK::Syntax(_), .. }));
252}
253
254#[cfg(test)]
255#[test]
256fn test_scan_ipv6addr() {
257    use ::ScanError as SE;
258    use ::ScanErrorKind as SEK;
259
260    macro_rules! check_ipv6 {
261        ($s:expr) => {
262            assert_match!(
263                <Ipv6Addr>::scan_from($s),
264                Ok((v, n)) if v == $s.parse().unwrap() && n == $s.len()
265            )
266        };
267
268        ($s:expr; Ok($v:expr)) => {
269            assert_match!(
270                <Ipv6Addr>::scan_from($s),
271                Ok((v, n)) if v == $v.parse().unwrap() && n == $v.len()
272            )
273        };
274
275        ($s:expr; Err($err:pat)) => {
276            assert_match!(
277                <Ipv6Addr>::scan_from($s),
278                Err($err)
279            )
280        };
281    }
282
283    check_ipv6!("0:0:0:0:0:0:0:0");
284    check_ipv6!("0:0:0:0:0:0:0:1");
285    check_ipv6!("::1");
286    check_ipv6!("::");
287    check_ipv6!("2a02:6b8::11:11");
288
289    check_ipv6!("::00000"; Err(SE { kind: SEK::Other(_), .. }));
290    check_ipv6!("1:2:3:4:5:6:7"; Err(SE { kind: SEK::Other(_), .. }));
291    check_ipv6!("1:2:3:4:5:6:7:8:9"; Err(SE { kind: SEK::Other(_), .. }));
292    check_ipv6!("1:2:::6:7:8"; Ok("1:2::"));
293    check_ipv6!("1:2::6::8"; Ok("1:2::6"));
294
295    check_ipv6!("::192.0.2.33");
296    check_ipv6!("::FFFF:192.0.2.33");
297    check_ipv6!("64:ff9b::192.0.2.33");
298    check_ipv6!("2001:db8:122:c000:2:2100:192.0.2.33");
299
300    check_ipv6!("::127.0.0.1:"; Ok("::127.0.0.1"));
301    check_ipv6!("1:2:3:4:5:127.0.0.1"; Err(SE { kind: SEK::Other(_), .. }));
302    check_ipv6!("1:2:3:4:5:6:7:127.0.0.1"; Err(SE { kind: SEK::Other(_), .. }));
303}
304
305#[cfg(test)]
306#[test]
307fn test_scan_socketaddr() {
308    use ::ScanError as SE;
309    use ::ScanErrorKind as SEK;
310
311    macro_rules! check_sockaddr {
312        ($s:expr) => {
313            assert_match!(
314                <SocketAddr>::scan_from($s),
315                Ok((v, n)) if v == $s.parse().unwrap() && n == $s.len()
316            )
317        };
318
319        ($s:expr; Ok($v:expr)) => {
320            assert_match!(
321                <SocketAddr>::scan_from($s),
322                Ok((v, n)) if v == $v.parse().unwrap() && n == $v.len()
323            )
324        };
325
326        ($s:expr; Err($err:pat)) => {
327            assert_match!(
328                <SocketAddr>::scan_from($s),
329                Err($err)
330            )
331        };
332    }
333
334    check_sockaddr!("0.0.0.0:0");
335    check_sockaddr!("127.0.0.1:80");
336    check_sockaddr!("255.255.255.255:65535");
337    check_sockaddr!("255.255.255.255:65536"; Err(SE { kind: SEK::Other(_), .. }));
338
339    check_sockaddr!("[0:0:0:0:0:0:0:0]:0");
340    check_sockaddr!("[0:0:0:0:0:0:0:1]:0");
341    check_sockaddr!("[::1]:0");
342    check_sockaddr!("[::]:0");
343    check_sockaddr!("[2a02:6b8::11:11]:0");
344}
345
346mod socket_addr_vx_scanners {
347    use std::net::{SocketAddrV4, SocketAddrV6};
348    use super::{match_ipv4_sock, match_ipv6_sock};
349    #[cfg(test)] use ::scanner::ScanFromStr;
350
351    parse_scanner! { impl<'a> for SocketAddrV4, matcher match_ipv4_sock, matcher err "expected IPv4 socket address", err map ScanError::other }
352    parse_scanner! { impl<'a> for SocketAddrV6, matcher match_ipv6_sock, matcher err "expected IPv6 socket address", err map ScanError::other }
353
354    #[cfg(test)]
355    #[test]
356    fn test_scan_socketaddrv4() {
357        use ::ScanError as SE;
358        use ::ScanErrorKind as SEK;
359
360        macro_rules! check_ipv4 {
361            ($s:expr) => {
362                assert_match!(
363                    <SocketAddrV4>::scan_from($s),
364                    Ok((v, n)) if v == $s.parse().unwrap() && n == $s.len()
365                )
366            };
367
368            ($s:expr; Ok($v:expr)) => {
369                assert_match!(
370                    <SocketAddrV4>::scan_from($s),
371                    Ok((v, n)) if v == $v.parse().unwrap() && n == $v.len()
372                )
373            };
374
375            ($s:expr; Err($err:pat)) => {
376                assert_match!(
377                    <SocketAddrV4>::scan_from($s),
378                    Err($err)
379                )
380            };
381        }
382
383        check_ipv4!("0.0.0.0:0");
384        check_ipv4!("127.0.0.1:80");
385        check_ipv4!("255.255.255.255:65535");
386        check_ipv4!("255.255.255.255:65536"; Err(SE { kind: SEK::Other(_), .. }));
387    }
388
389    #[cfg(test)]
390    #[test]
391    fn test_scan_socketaddrv6() {
392        macro_rules! check_ipv6 {
393            ($s:expr) => {
394                assert_match!(
395                    <SocketAddrV6>::scan_from($s),
396                    Ok((v, n)) if v == $s.parse().unwrap() && n == $s.len()
397                )
398            };
399
400            ($s:expr; Ok($v:expr)) => {
401                assert_match!(
402                    <SocketAddrV6>::scan_from($s),
403                    Ok((v, n)) if v == $v.parse().unwrap() && n == $v.len()
404                )
405            };
406
407            ($s:expr; Err($err:pat)) => {
408                assert_match!(
409                    <SocketAddrV6>::scan_from($s),
410                    Err($err)
411                )
412            };
413        }
414
415        check_ipv6!("[0:0:0:0:0:0:0:0]:0");
416        check_ipv6!("[0:0:0:0:0:0:0:1]:0");
417        check_ipv6!("[::1]:0");
418        check_ipv6!("[::]:0");
419        check_ipv6!("[2a02:6b8::11:11]:0");
420    }
421}