antidns/
extract.rs

1use std::{convert::TryFrom, net::Ipv4Addr};
2
3use nom::{
4    character::complete::{char, digit1},
5    combinator::map_res,
6    sequence::tuple,
7    IResult,
8};
9use snafu::{ensure, Snafu};
10
11#[derive(Debug, Snafu)]
12pub enum Error {
13    NameWithoutIp,
14    FailedToParse { message: String },
15    IncompleteParse,
16}
17
18fn digit(i: &str) -> IResult<&str, u8> {
19    map_res(digit1, |int_val: &str| int_val.parse::<u8>())(i)
20}
21
22fn ip_address(i: &str) -> IResult<&str, Ipv4Addr> {
23    map_res(
24        tuple((digit, char('-'), digit, char('-'), digit, char('-'), digit)),
25        |(a, _, b, _, c, _, d)| Ipv4Addr::try_from([a, b, c, d]),
26    )(i)
27}
28
29pub fn ip_address_from_url<S: AsRef<str>>(url: S) -> Result<Ipv4Addr, Error> {
30    let splitted: Vec<_> = url.as_ref().split('.').collect();
31    ensure!(splitted.len() >= 2, NameWithoutIpSnafu);
32
33    let ip_segment = *splitted.first().unwrap();
34    let (rest, ip) = ip_address(ip_segment).map_err(|e| Error::FailedToParse {
35        message: e.to_string(),
36    })?;
37    ensure!(rest.is_empty(), IncompleteParseSnafu);
38
39    Ok(ip)
40}