Skip to main content

Mist/
Zone.rs

1#![allow(non_camel_case_types, non_upper_case_globals)]
2//! # DNS Zone
3//!
4//! Provides DNS zone configuration for the CodeEditorLand private network.
5//! Creates an authoritative zone for `editor.land` that resolves to loopback
6//! addresses.
7
8use anyhow::Result;
9use hickory_proto::rr::{
10	Name,
11	RData,
12	Record,
13	rdata::{A, NS, SOA},
14};
15// hickory-server 0.26: see the block comment in `Server.rs` for the full
16// rename table (`authority::*` → `zone_handler::*`, `InMemoryAuthority` →
17// `InMemoryZoneHandler`, AXFR bool → `AxfrPolicy`). The handler became
18// generic over `P: RuntimeProvider`; we pin it to `TokioRuntimeProvider` so
19// return types are concrete and callers don't have to thread the parameter.
20use hickory_server::{
21	net::runtime::TokioRuntimeProvider,
22	store::in_memory::InMemoryZoneHandler,
23	zone_handler::{AxfrPolicy, ZoneType},
24};
25
26/// Creates the `editor.land` authoritative zone records.
27///
28/// All `*.editor.land` domains resolve to `127.x.x.x` (loopback).
29pub fn EditorLandZone() -> Result<Vec<Record>> {
30	let mut Records = Vec::new();
31
32	let Origin = Name::from_ascii("editor.land.").unwrap();
33
34	let TTL = 300u32;
35
36	let Serial = 2025010100u32;
37
38	let Refresh:i32 = 86400;
39
40	let Retry:i32 = 7200;
41
42	let Expire:i32 = 604800;
43
44	let Minimum:u32 = 3600;
45
46	let SOARecord = SOA::new(
47		Name::from_ascii("ns1.editor.land.").unwrap(),
48		Name::from_ascii("hostmaster.editor.land.").unwrap(),
49		Serial,
50		Refresh,
51		Retry,
52		Expire,
53		Minimum,
54	);
55
56	Records.push(Record::from_rdata(Origin.clone(), TTL, RData::SOA(SOARecord)));
57
58	let NSName = Name::from_ascii("ns1.editor.land.").unwrap();
59
60	Records.push(Record::from_rdata(Origin.clone(), TTL, RData::NS(NS(NSName))));
61
62	Records.push(Record::from_rdata(
63		Name::from_ascii("ns1.editor.land.").unwrap(),
64		TTL,
65		RData::A(A::new(127, 0, 0, 1)),
66	));
67
68	let Subdomains = vec!["editor", "www", "localhost", "sidecar", "cocoon"];
69
70	for (Index, Subdomain) in Subdomains.iter().enumerate() {
71		let SubdomainName = Name::from_ascii(format!("{}.editor.land.", Subdomain)).unwrap();
72
73		let IP = A::new(127, 0, (Index / 255) as u8, (Index % 255) as u8);
74
75		Records.push(Record::from_rdata(SubdomainName, TTL, RData::A(IP)));
76	}
77
78	Records.push(Record::from_rdata(Origin, TTL, RData::A(A::new(127, 0, 0, 1))));
79
80	Ok(Records)
81}
82
83/// Creates an `InMemoryZoneHandler` for the `editor.land` zone.
84pub fn EditorLandAuthority() -> Result<InMemoryZoneHandler<TokioRuntimeProvider>> {
85	let Origin = Name::from_ascii("editor.land.").unwrap();
86
87	let Authority =
88		InMemoryZoneHandler::<TokioRuntimeProvider>::empty(Origin, ZoneType::Primary, AxfrPolicy::Deny, None);
89
90	let _Records = EditorLandZone()?;
91
92	Ok(Authority)
93}
94
95/// Creates an `InMemoryZoneHandler` for a custom origin with specified records.
96pub fn CustomAuthority(Origin:&Name, _Records:Vec<Record>) -> Result<InMemoryZoneHandler<TokioRuntimeProvider>> {
97	let Authority =
98		InMemoryZoneHandler::<TokioRuntimeProvider>::empty(Origin.clone(), ZoneType::Primary, AxfrPolicy::Deny, None);
99
100	Ok(Authority)
101}
102
103#[cfg(test)]
104mod tests {
105
106	use hickory_server::zone_handler::ZoneHandler;
107
108	use super::*;
109
110	#[test]
111	fn TestZoneCreation() {
112		let Zone = EditorLandZone().expect("Failed to create zone");
113
114		assert!(!Zone.is_empty());
115	}
116
117	#[test]
118	fn TestZoneHasLoopbackRecords() {
119		let Zone = EditorLandZone().expect("Failed to create zone");
120
121		for Record in &Zone {
122			if let RData::A(IP) = Record.data() {
123				assert_eq!(IP.octets()[0], 127, "A record must resolve to 127.x.x.x");
124			}
125		}
126	}
127}