Skip to content

Commit a4af651

Browse files
committed
f - Allow configuring Human-Readable Name resolution
Addresses review feedback on the initial HRN configuration commit: - Construct `HRNResolverConfig::Dns` explicitly inside the DNS arm of the mode match rather than relying on `HumanReadableNamesConfig`'s default being DNS. If LDK Node's default ever changes (e.g., to accommodate new resolver modes), the DNS-specific settings are still applied when the user explicitly selects DNS mode instead of being silently dropped. - Reject configs that set `dns_server_address` or `enable_resolution_service` under `mode = "blip32"`, since these options would otherwise be silently ignored and leave users thinking they took effect. - Fall back to port 53 when a DNS server address is given without an explicit port (e.g., `dns_server_address = "1.1.1.1"` is treated as `"1.1.1.1:53"`), matching the convention for DNS. Generated with the assistance of AI (Claude).
1 parent f008439 commit a4af651

3 files changed

Lines changed: 106 additions & 30 deletions

File tree

contrib/ldk-server-config.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ poll_metrics_interval = 60 # The polling interval for metrics in seconds.
109109
# Resolution method: "dns" (resolve locally via a DNS server) or "blip32" (ask other
110110
# nodes to resolve for us via bLIP-32). Defaults to "dns".
111111
#mode = "dns"
112-
# DNS server used when `mode = "dns"`. Defaults to 8.8.8.8:53 (Google Public DNS).
112+
# DNS server used when `mode = "dns"`. Defaults to 8.8.8.8:53 (Google Public DNS). The
113+
# port defaults to 53 if omitted (e.g., "1.1.1.1" is treated as "1.1.1.1:53").
113114
#dns_server_address = "8.8.8.8:53"
114115
# When set to true (and `mode = "dns"`), also offer HRN resolution to the rest of the
115116
# network over Onion Messages. Requires the node to be announceable so resolution

docs/configuration.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,14 @@ Human-Readable Names (e.g., `₿alice@example.com`) to Lightning payment destina
131131
Two resolution methods are supported via the `mode` field:
132132

133133
- **`"dns"`** (default) - Resolve names locally using a DNS server. The server is set via
134-
`dns_server_address` (default: `8.8.8.8:53`, Google Public DNS). When
135-
`enable_resolution_service = true`, the node additionally offers HRN resolution to the
136-
rest of the network over Onion Messages. This requires the node to be announceable so
137-
resolution requests can be routed to it, and is therefore disabled by default.
134+
`dns_server_address` (default: `8.8.8.8:53`, Google Public DNS). The port defaults to
135+
`53` if omitted. When `enable_resolution_service = true`, the node additionally offers
136+
HRN resolution to the rest of the network over Onion Messages. This requires the node
137+
to be announceable so resolution requests can be routed to it, and is therefore
138+
disabled by default.
138139
- **`"blip32"`** - Ask other nodes to resolve names on our behalf via
139-
[bLIP-32](https://github.com/lightning/blips/blob/master/blip-0032.md).
140+
[bLIP-32](https://github.com/lightning/blips/blob/master/blip-0032.md). `dns_server_address`
141+
and `enable_resolution_service` only apply in `"dns"` mode and are rejected here.
140142

141143
## Storage Layout
142144

ldk-server/src/util/config.rs

Lines changed: 97 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -530,39 +530,80 @@ impl TryFrom<HrnTomlConfig> for HumanReadableNamesConfig {
530530
type Error = io::Error;
531531

532532
fn try_from(value: HrnTomlConfig) -> Result<Self, Self::Error> {
533-
let mut config = HumanReadableNamesConfig::default();
534-
535-
match value.mode.as_deref() {
536-
None | Some("dns") => {},
533+
let HrnTomlConfig { mode, dns_server_address, enable_resolution_service } = value;
534+
535+
let resolution_config = match mode.as_deref() {
536+
None | Some("dns") => {
537+
// Start from LDK Node's DNS defaults so we don't have to hardcode them, but fall
538+
// back to explicit values if the upstream default ever stops being `Dns`.
539+
let (mut dns_server_address_val, mut enable_hrn_resolution_service) =
540+
if let HRNResolverConfig::Dns {
541+
dns_server_address,
542+
enable_hrn_resolution_service,
543+
} = HumanReadableNamesConfig::default().resolution_config
544+
{
545+
(dns_server_address, enable_hrn_resolution_service)
546+
} else {
547+
(
548+
SocketAddress::from_str("8.8.8.8:53")
549+
.expect("`8.8.8.8:53` is a valid socket address"),
550+
false,
551+
)
552+
};
553+
554+
if let Some(addr) = dns_server_address.as_deref() {
555+
dns_server_address_val = parse_dns_server_address(addr)?;
556+
}
557+
if let Some(enable) = enable_resolution_service {
558+
enable_hrn_resolution_service = enable;
559+
}
560+
561+
HRNResolverConfig::Dns {
562+
dns_server_address: dns_server_address_val,
563+
enable_hrn_resolution_service,
564+
}
565+
},
537566
Some("blip32") => {
538-
config.resolution_config = HRNResolverConfig::Blip32;
567+
if dns_server_address.is_some() {
568+
return Err(io::Error::new(
569+
io::ErrorKind::InvalidInput,
570+
"`hrn.dns_server_address` only applies when `hrn.mode = \"dns\"`"
571+
.to_string(),
572+
));
573+
}
574+
if enable_resolution_service.is_some() {
575+
return Err(io::Error::new(
576+
io::ErrorKind::InvalidInput,
577+
"`hrn.enable_resolution_service` only applies when `hrn.mode = \"dns\"`"
578+
.to_string(),
579+
));
580+
}
581+
HRNResolverConfig::Blip32
539582
},
540583
Some(other) => {
541584
return Err(io::Error::new(
542585
io::ErrorKind::InvalidInput,
543586
format!("Invalid HRN mode '{}' configured; expected 'dns' or 'blip32'", other),
544587
))
545588
},
546-
}
589+
};
547590

548-
if let HRNResolverConfig::Dns { dns_server_address, enable_hrn_resolution_service } =
549-
&mut config.resolution_config
550-
{
551-
if let Some(addr) = value.dns_server_address.as_deref() {
552-
*dns_server_address = SocketAddress::from_str(addr).map_err(|e| {
553-
io::Error::new(
554-
io::ErrorKind::InvalidInput,
555-
format!("Invalid HRN DNS server address configured: {}", e),
556-
)
557-
})?;
558-
}
559-
if let Some(enable) = value.enable_resolution_service {
560-
*enable_hrn_resolution_service = enable;
561-
}
562-
}
591+
Ok(HumanReadableNamesConfig { resolution_config })
592+
}
593+
}
563594

564-
Ok(config)
595+
/// Parses a DNS server address, falling back to port 53 if the user omitted the port.
596+
fn parse_dns_server_address(addr: &str) -> io::Result<SocketAddress> {
597+
if let Ok(sa) = SocketAddress::from_str(addr) {
598+
return Ok(sa);
565599
}
600+
let with_default_port = format!("{}:53", addr);
601+
SocketAddress::from_str(&with_default_port).map_err(|e| {
602+
io::Error::new(
603+
io::ErrorKind::InvalidInput,
604+
format!("Invalid HRN DNS server address configured: {}", e),
605+
)
606+
})
566607
}
567608

568609
#[derive(Deserialize, Serialize)]
@@ -1634,11 +1675,43 @@ mod tests {
16341675
let err = load_config(&args_config).unwrap_err();
16351676
assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
16361677

1637-
// Invalid DNS server address is rejected.
1678+
// Invalid DNS server address is rejected (contains chars disallowed in hostnames, so
1679+
// neither the as-is parse nor the `:53` fallback can accept it).
16381680
let toml_config =
1639-
format!("{}\n[hrn]\ndns_server_address = \"not-a-socket-address\"\n", base_config);
1681+
format!("{}\n[hrn]\ndns_server_address = \"invalid@address\"\n", base_config);
1682+
fs::write(storage_path.join(config_file_name), &toml_config).unwrap();
1683+
let err = load_config(&args_config).unwrap_err();
1684+
assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
1685+
1686+
// DNS server address without an explicit port defaults to port 53.
1687+
let toml_config = format!("{}\n[hrn]\ndns_server_address = \"1.1.1.1\"\n", base_config);
1688+
fs::write(storage_path.join(config_file_name), &toml_config).unwrap();
1689+
let config = load_config(&args_config).unwrap();
1690+
match config.hrn_config.resolution_config {
1691+
HRNResolverConfig::Dns { dns_server_address, .. } => {
1692+
assert_eq!(dns_server_address, SocketAddress::from_str("1.1.1.1:53").unwrap());
1693+
},
1694+
other => panic!("unexpected HRN resolver config: {:?}", other),
1695+
}
1696+
1697+
// `blip32` mode combined with DNS-only settings is rejected so users aren't confused
1698+
// by settings that would silently have no effect.
1699+
let toml_config = format!(
1700+
"{}\n[hrn]\nmode = \"blip32\"\ndns_server_address = \"1.1.1.1:53\"\n",
1701+
base_config
1702+
);
1703+
fs::write(storage_path.join(config_file_name), &toml_config).unwrap();
1704+
let err = load_config(&args_config).unwrap_err();
1705+
assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
1706+
assert!(err.to_string().contains("dns_server_address"));
1707+
1708+
let toml_config = format!(
1709+
"{}\n[hrn]\nmode = \"blip32\"\nenable_resolution_service = true\n",
1710+
base_config
1711+
);
16401712
fs::write(storage_path.join(config_file_name), &toml_config).unwrap();
16411713
let err = load_config(&args_config).unwrap_err();
16421714
assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
1715+
assert!(err.to_string().contains("enable_resolution_service"));
16431716
}
16441717
}

0 commit comments

Comments
 (0)