Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add support for https-record #396

Merged
merged 1 commit into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(nightly)'] }

[features]

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

homebrew = ["dns-over-tls", "dns-over-https", "dns-over-quic", "dns-over-h3", "dnssec", "service", "nft" ]
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-ipv4 = []
nom-recipes-ipv6 = []

failed_tests = []
disable_icmp_ping = []
Expand Down
6 changes: 4 additions & 2 deletions src/config/domain_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ pub struct DomainRule {

pub address: Option<DomainAddress>,

pub cname: Option<CName>,
pub cname: Option<CNameRule>,

pub srv: Option<SRV>,

pub https: Option<HttpsRecordRule>,

/// The mode of speed checking.
pub speed_check_mode: Option<SpeedCheckModeList>,

Expand All @@ -23,7 +25,7 @@ pub struct DomainRule {

pub no_cache: Option<bool>,
pub no_serve_expired: Option<bool>,
pub nftset: Option<Vec<ConfigForIP<NftsetConfig>>>,
pub nftset: Option<Vec<ConfigForIP<NFTsetConfig>>>,

pub rr_ttl: Option<u64>,
pub rr_ttl_min: Option<u64>,
Expand Down
28 changes: 23 additions & 5 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use std::{

use crate::{
infra::{file_mode::FileMode, ipset::IpSet},
libdns::proto::rr::{rdata::SRV, Name, RecordType},
libdns::proto::rr::{
rdata::{HTTPS, SRV},
Name, RecordType,
},
log::Level,
proxy::ProxyConfig,
third_ext::serde_str,
Expand Down Expand Up @@ -48,8 +51,9 @@ pub type DomainSets = HashMap<String, HashSet<WildcardName>>;
pub type ForwardRules = Vec<ForwardRule>;
pub type AddressRules = Vec<AddressRule>;
pub type DomainRules = Vec<ConfigForDomain<DomainRule>>;
pub type CNameRules = Vec<ConfigForDomain<CName>>;
pub type CNameRules = Vec<ConfigForDomain<CNameRule>>;
pub type SrvRecords = Vec<ConfigForDomain<SRV>>;
pub type HttpsRecords = Vec<ConfigForDomain<HttpsRecordRule>>;

#[derive(Default)]
pub struct Config {
Expand Down Expand Up @@ -237,10 +241,12 @@ pub struct Config {

pub srv_records: SrvRecords,

pub https_records: HttpsRecords,

/// The proxy server for upstream querying.
pub proxy_servers: HashMap<String, ProxyConfig>,

pub nftsets: Vec<ConfigForDomain<Vec<ConfigForIP<NftsetConfig>>>>,
pub nftsets: Vec<ConfigForDomain<Vec<ConfigForIP<NFTsetConfig>>>>,

pub resolv_file: Option<PathBuf>,
pub domain_set_providers: HashMap<String, Vec<DomainSetProvider>>,
Expand Down Expand Up @@ -274,7 +280,7 @@ pub enum ConfigForIP<T: Sized + parser::NomParser> {
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NftsetConfig {
pub struct NFTsetConfig {
pub family: &'static str,
pub table: String,
pub name: String,
Expand Down Expand Up @@ -331,7 +337,7 @@ pub enum Ignorable<T> {
Value(T),
}

pub type CName = Ignorable<Name>;
pub type CNameRule = Ignorable<Name>;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AddressRule {
Expand All @@ -349,6 +355,18 @@ pub struct ForwardRule {
pub nameserver: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[allow(clippy::upper_case_acronyms)]
pub enum HttpsRecordRule {
SOA,
Ignore,
Filter {
no_ipv4_hint: bool,
no_ipv6_hint: bool,
},
RecordData(HTTPS),
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pymumu Hello, 这个 https-record 是否可以表示成这样的枚举,4 种互斥的配置。

看文档,不确定 no_ipv4_hint 和 RecordData 能否并存。


macro_rules! impl_from_str {
($($type:ty),*) => {
$(
Expand Down
12 changes: 6 additions & 6 deletions src/config/parser/cname.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::*;

impl NomParser for CName {
impl NomParser for CNameRule {
fn parse(input: &str) -> IResult<&str, Self> {
alt((
value(CName::IGN, char('-')),
map(NomParser::parse, CName::Value),
value(CNameRule::IGN, char('-')),
map(NomParser::parse, CNameRule::Value),
))(input)
}
}
Expand All @@ -16,10 +16,10 @@ mod tests {

#[test]
fn test() {
assert_eq!(CName::parse("-"), Ok(("", CName::IGN)));
assert_eq!(CNameRule::parse("-"), Ok(("", CNameRule::IGN)));
assert_eq!(
CName::parse("example.com"),
Ok(("", CName::Value("example.com".parse().unwrap())))
CNameRule::parse("example.com"),
Ok(("", CNameRule::Value("example.com".parse().unwrap())))
);
}
}
23 changes: 20 additions & 3 deletions src/config/parser/config_for_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use super::*;

impl<T: NomParser + Clone> NomParser for ConfigForDomain<T> {
fn parse(input: &str) -> IResult<&str, Self> {
let domain = delimited(char('/'), Domain::parse, char('/'));
let domain = map(opt(delimited(char('/'), Domain::parse, char('/'))), |n| {
n.unwrap_or_else(|| Domain::Name(WildcardName::Default(Name::root())))
});
let config = T::parse;
map(
pair(domain, preceded(space0, config)),
Expand All @@ -23,7 +25,7 @@ mod tests {
"",
ConfigForDomain {
domain: Domain::Name("www.example.com".parse().unwrap()),
config: ConfigForIP::V4(NftsetConfig {
config: ConfigForIP::V4(NFTsetConfig {
family: "inet",
table: "tab".to_string(),
name: "dns4".to_string()
Expand All @@ -38,7 +40,22 @@ mod tests {
"",
ConfigForDomain {
domain: Domain::Set("abc".to_string()),
config: ConfigForIP::V6(NftsetConfig {
config: ConfigForIP::V6(NFTsetConfig {
family: "inet",
table: "tab".to_string(),
name: "dns4".to_string()
})
}
)
);

assert_eq!(
ConfigForDomain::parse("#6:inet#tab#dns4").unwrap(),
(
"",
ConfigForDomain {
domain: Domain::Name(WildcardName::Default(Name::root())),
config: ConfigForIP::V6(NFTsetConfig {
family: "inet",
table: "tab".to_string(),
name: "dns4".to_string()
Expand Down
101 changes: 101 additions & 0 deletions src/config/parser/https_record.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use super::*;

impl NomParser for HttpsRecordRule {
fn parse(input: &str) -> IResult<&str, Self> {
alt((
map(char('#'), |_| Self::SOA),
map(char('-'), |_| Self::Ignore),
map(
separated_list1(
char(','),
delimited(
space0,
alt((
value(4u8, tag_no_case("noipv4hint")),
value(6u8, tag_no_case("noipv6hint")),
)),
space0,
),
),
|no_hints| Self::Filter {
no_ipv4_hint: no_hints.contains(&4),
no_ipv6_hint: no_hints.contains(&6),
},
),
map(NomParser::parse, Self::RecordData),
))(input)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::libdns::proto::rr::rdata::svcb::{Alpn, IpHint, SvcParamKey, SvcParamValue, SVCB};

#[test]
fn test_parse() {
assert_eq!(HttpsRecordRule::parse("#"), Ok(("", HttpsRecordRule::SOA)));
assert_eq!(
HttpsRecordRule::parse("-"),
Ok(("", HttpsRecordRule::Ignore))
);
assert_eq!(
HttpsRecordRule::parse("noipv4hint"),
Ok((
"",
HttpsRecordRule::Filter {
no_ipv4_hint: true,
no_ipv6_hint: false
}
))
);
assert_eq!(
HttpsRecordRule::parse("noipv6hint, noipv4hint"),
Ok((
"",
HttpsRecordRule::Filter {
no_ipv4_hint: true,
no_ipv6_hint: true
}
))
);
assert_eq!(
HttpsRecordRule::parse(r#"alpn="h2,http/1.1""#),
Ok((
"",
HttpsRecordRule::RecordData(HTTPS(SVCB::new(
0,
".".parse().unwrap(),
vec![(
SvcParamKey::Alpn,
SvcParamValue::Alpn(Alpn(vec!["h2".to_string(), "http/1.1".to_string()]))
),]
)))
))
);

assert_eq!(
HttpsRecordRule::parse(r#"ipv4hint=127.0.0.1,ipv6hint="::1, 2001:db8::1""#),
Ok((
"",
HttpsRecordRule::RecordData(HTTPS(SVCB::new(
0,
".".parse().unwrap(),
vec![
(
SvcParamKey::Ipv4Hint,
SvcParamValue::Ipv4Hint(IpHint(vec!["127.0.0.1".parse().unwrap()]))
),
(
SvcParamKey::Ipv6Hint,
SvcParamValue::Ipv6Hint(IpHint(vec![
"::1".parse().unwrap(),
"2001:db8::1".parse().unwrap()
]))
)
]
)))
))
);
}
}
17 changes: 11 additions & 6 deletions src/config/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@ mod domain_set;
mod file_mode;
mod forward_rule;
mod glob_pattern;
mod https_record;
mod ipnet;
mod listener;
mod log_level;
mod nameserver;
mod nftset;
mod nom_recipes;
mod options;
mod path;
mod proxy_config;
mod record_type;
mod response_mode;
mod speed_mode;
mod srv;
mod svcb;

use super::*;

Expand Down Expand Up @@ -91,8 +94,9 @@ pub enum OneConfig {
CacheCheckpointTime(u64),
CaFile(PathBuf),
CaPath(PathBuf),
CNAME(ConfigForDomain<CName>),
SRV(ConfigForDomain<SRV>),
CNAME(ConfigForDomain<CNameRule>),
SrvRecord(ConfigForDomain<SRV>),
HttpsRecord(ConfigForDomain<HttpsRecordRule>),
ConfFile(PathBuf),
DnsmasqLeaseFile(PathBuf),
Domain(Name),
Expand All @@ -119,7 +123,7 @@ pub enum OneConfig {
LogFilter(String),
MaxReplyIpNum(u8),
MdnsLookup(bool),
NftSet(ConfigForDomain<Vec<ConfigForIP<NftsetConfig>>>),
NftSet(ConfigForDomain<Vec<ConfigForIP<NFTsetConfig>>>),
NumWorkers(usize),
PrefetchDomain(bool),
ProxyConfig(NamedProxyConfig),
Expand Down Expand Up @@ -205,6 +209,7 @@ pub fn parse_config(input: &str) -> IResult<&str, OneConfig> {
map(parse_item("num-workers"), OneConfig::NumWorkers),
map(parse_item("domain"), OneConfig::Domain),
map(parse_item("hosts-file"), OneConfig::HostsFile),
map(parse_item("https-record"), OneConfig::HttpsRecord),
map(parse_item("local-ttl"), OneConfig::LocalTtl),
map(parse_item("log-console"), OneConfig::LogConsole),
map(parse_item("log-file-mode"), OneConfig::LogFileMode),
Expand Down Expand Up @@ -238,7 +243,7 @@ pub fn parse_config(input: &str) -> IResult<&str, OneConfig> {
));

let group4 = alt((
map(parse_item("srv-record"), OneConfig::SRV),
map(parse_item("srv-record"), OneConfig::SrvRecord),
map(parse_item("resolv-hostname"), OneConfig::ResolvHostname),
map(parse_item("tcp-idle-time"), OneConfig::TcpIdleTime),
map(parse_item("nftset"), OneConfig::NftSet),
Expand All @@ -264,7 +269,7 @@ mod tests {
"",
OneConfig::NftSet(ConfigForDomain {
domain: Domain::Name("www.example.com".parse().unwrap()),
config: vec![ConfigForIP::V4(NftsetConfig {
config: vec![ConfigForIP::V4(NFTsetConfig {
family: "inet",
table: "tab".to_string(),
name: "dns4".to_string()
Expand All @@ -279,7 +284,7 @@ mod tests {
"",
OneConfig::NftSet(ConfigForDomain {
domain: Domain::Name("www.example.com".parse().unwrap()),
config: vec![ConfigForIP::V4(NftsetConfig {
config: vec![ConfigForIP::V4(NFTsetConfig {
family: "inet",
table: "tab".to_string(),
name: "dns4".to_string()
Expand Down
Loading