Skip to content

Commit

Permalink
🐛 Return IPv6-mapped address when querying AAAA for set IPv4 address
Browse files Browse the repository at this point in the history
Address rule allows to set multipile addresses.
  • Loading branch information
mokeyish authored Oct 19, 2024
1 parent 8c0347b commit 4445811
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 142 deletions.
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ default = ["dns-over-tls", "dns-over-https", "dns-over-quic", "dns-over-h3", "dn

homebrew = ["dns-over-tls", "dns-over-https", "dns-over-quic", "dns-over-h3", "dnssec", "service", "nft", "nom-recipes-all" ]

nom-recipes-all =["nom-recipes-ipv4", "nom-recipes-ipv6"]
nom-recipes-all =["nom-recipes-ip"]

nom-recipes-ip = ["nom-recipes-ipv4", "nom-recipes-ipv6"]
nom-recipes-ipv4 = []
nom-recipes-ipv6 = []
nom-recipes-ipv6 = [
"nom-recipes-ipv4" # support IPv4-mapped IPv6 addresses
]

failed_tests = []
disable_icmp_ping = []
Expand Down
2 changes: 1 addition & 1 deletion src/config/domain_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct DomainRule {
/// The name of NameServer Group.
pub nameserver: Option<String>,

pub address: Option<DomainAddress>,
pub address: Option<AddressRuleValue>,

pub cname: Option<CNameRule>,

Expand Down
45 changes: 35 additions & 10 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{
net::{Ipv4Addr, Ipv6Addr},
path::PathBuf,
str::FromStr,
sync::Arc,
};

use crate::{
Expand Down Expand Up @@ -301,30 +302,54 @@ pub struct SslConfig {
}

#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum DomainAddress {
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum AddressRuleValue {
SOA,
SOAv4,
SOAv6,
IGN,
IGNv4,
IGNv6,
IPv4(Ipv4Addr),
IPv6(Ipv6Addr),
Addr {
v4: Option<Arc<[Ipv4Addr]>>,
v6: Option<Arc<[Ipv6Addr]>>,
},
}

impl std::fmt::Display for DomainAddress {
impl std::fmt::Display for AddressRuleValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use DomainAddress::*;
use AddressRuleValue::*;
match self {
SOA => write!(f, "#"),
SOAv4 => write!(f, "#4"),
SOAv6 => write!(f, "#6"),
IGN => write!(f, "-"),
IGNv4 => write!(f, "-4"),
IGNv6 => write!(f, "-6"),
IPv4(ip) => write!(f, "{ip}"),
IPv6(ip) => write!(f, "{ip}"),
Addr { v4, v6 } => {
let mut first = true;
if let Some(v4) = v4 {
for ip in v4.iter() {
if first {
first = false;
} else {
write!(f, ",")?;
}
write!(f, "{}", ip)?;
}
}
if let Some(v6) = v6 {
for ip in v6.iter() {
if first {
first = false;
} else {
write!(f, ",")?;
}
write!(f, "{}", ip)?;
}
}
Ok(())
}
}
}
}
Expand All @@ -344,7 +369,7 @@ pub struct AddressRule {
#[serde(with = "serde_str")]
pub domain: Domain,
#[serde(with = "serde_str")]
pub address: DomainAddress,
pub address: AddressRuleValue,
}

/// alias: nameserver rules
Expand Down Expand Up @@ -384,4 +409,4 @@ macro_rules! impl_from_str {
};
}

impl_from_str!(AddressRule, Domain, DomainAddress, ListenerAddress);
impl_from_str!(AddressRule, Domain, AddressRuleValue, ListenerAddress);
83 changes: 80 additions & 3 deletions src/config/parser/address_rule.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::net::IpAddr;

use super::*;

impl NomParser for AddressRule {
Expand All @@ -12,6 +14,38 @@ impl NomParser for AddressRule {
}
}

impl NomParser for AddressRuleValue {
fn parse(input: &str) -> IResult<&str, Self> {
use AddressRuleValue::*;

let soa = value(SOA, char('#'));
let soa_v4 = value(SOAv4, tag("#4"));
let soa_v6 = value(SOAv6, tag("#6"));
let ign = value(IGN, tag("-"));
let ign_v4 = value(IGNv4, tag("-4"));
let ign_v6 = value(IGNv6, tag("-6"));

let ip_addrs = map(
separated_list1(tuple((space0, char(','), space0)), nom_recipes::ip),
|ip_addrs| {
let mut v4 = vec![];
let mut v6 = vec![];
for ip_addr in ip_addrs {
match ip_addr {
IpAddr::V4(ip) => v4.push(ip),
IpAddr::V6(ip) => v6.push(ip),
}
}
let v4 = if v4.is_empty() { None } else { Some(v4.into()) };
let v6 = if v6.is_empty() { None } else { Some(v6.into()) };
Addr { v4, v6 }
},
);

alt((soa_v4, soa_v6, soa, ign_v4, ign_v6, ign, ip_addrs))(input)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -24,7 +58,7 @@ mod tests {
"",
AddressRule {
domain: Domain::Name(WildcardName::Default("example.com".parse().unwrap())),
address: DomainAddress::SOA
address: AddressRuleValue::SOA
}
))
);
Expand All @@ -38,7 +72,7 @@ mod tests {
"",
AddressRule {
domain: Domain::Name(WildcardName::Suffix(Name::root())),
address: DomainAddress::SOA
address: AddressRuleValue::SOA
}
))
);
Expand All @@ -52,7 +86,50 @@ mod tests {
"",
AddressRule {
domain: Domain::Name(WildcardName::Full("example.com".parse().unwrap())),
address: DomainAddress::SOA
address: AddressRuleValue::SOA
}
))
);
}

#[test]
fn test_parse_rule_value() {
use AddressRuleValue::*;
assert_eq!(AddressRuleValue::parse("#"), Ok(("", SOA)));
assert_eq!(AddressRuleValue::parse("#4"), Ok(("", SOAv4)));
assert_eq!(AddressRuleValue::parse("#6"), Ok(("", SOAv6)));
assert_eq!(AddressRuleValue::parse("-"), Ok(("", IGN)));
assert_eq!(AddressRuleValue::parse("-4"), Ok(("", IGNv4)));
assert_eq!(AddressRuleValue::parse("-6"), Ok(("", IGNv6)));

assert_eq!(
AddressRuleValue::parse("127.0.0.1"),
Ok((
"",
Addr {
v4: Some(["127.0.0.1".parse().unwrap()].into()),
v6: None
}
))
);
assert_eq!(
AddressRuleValue::parse("::1"),
Ok((
"",
Addr {
v4: None,
v6: Some(["::1".parse().unwrap()].into())
}
))
);

assert_eq!(
AddressRuleValue::parse("::1, 127.0.0.1"),
Ok((
"",
Addr {
v4: Some(["127.0.0.1".parse().unwrap()].into()),
v6: Some(["::1".parse().unwrap()].into())
}
))
);
Expand Down
45 changes: 0 additions & 45 deletions src/config/parser/domain_policy.rs

This file was deleted.

32 changes: 30 additions & 2 deletions src/config/parser/domain_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ mod tests {
Ok((
"",
DomainRule {
address: Some(DomainAddress::IGN),
address: Some(AddressRuleValue::IGN),
..Default::default()
}
))
Expand All @@ -141,7 +141,7 @@ mod tests {
Ok((
"",
DomainRule {
address: Some(DomainAddress::SOAv6),
address: Some(AddressRuleValue::SOAv6),
..Default::default()
}
))
Expand Down Expand Up @@ -178,5 +178,33 @@ mod tests {
}
))
);

assert_eq!(
DomainRule::parse("-a 127.0.0.1"),
Ok((
"",
DomainRule {
address: Some(AddressRuleValue::Addr {
v4: Some(["127.0.0.1".parse().unwrap()].into()),
v6: None
}),
..Default::default()
}
))
);

assert_eq!(
DomainRule::parse("-a 127.0.0.1,::1"),
Ok((
"",
DomainRule {
address: Some(AddressRuleValue::Addr {
v4: Some(["127.0.0.1".parse().unwrap()].into()),
v6: Some(["::1".parse().unwrap()].into())
}),
..Default::default()
}
))
);
}
}
3 changes: 1 addition & 2 deletions src/config/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ mod bytes;
mod cname;
mod config_for_domain;
mod domain;
mod domain_policy;
mod domain_rule;
mod domain_set;
mod file_mode;
Expand Down Expand Up @@ -361,7 +360,7 @@ mod tests {
OneConfig::DomainRule(ConfigForDomain {
domain: Domain::Set("domain-block-list".to_string()),
config: DomainRule {
address: Some(DomainAddress::SOA),
address: Some(AddressRuleValue::SOA),
..Default::default()
}
})
Expand Down
8 changes: 8 additions & 0 deletions src/config/parser/nom_recipes/ip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use std::net::IpAddr;

use super::{ipv4, ipv6};
use nom::{branch::alt, combinator::map, IResult};

pub fn ip(input: &str) -> IResult<&str, IpAddr> {
alt((map(ipv4, IpAddr::from), map(ipv6, IpAddr::from)))(input)
}
Loading

0 comments on commit 4445811

Please sign in to comment.