Skip to content

Commit be5028d

Browse files
committed
refactor(zone.rs): Change fn from_master_file and tests for the same fn. It compiles.
1 parent 5eecffd commit be5028d

File tree

1 file changed

+162
-89
lines changed

1 file changed

+162
-89
lines changed

src/zones.rs

Lines changed: 162 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use crate::message::rdata::a_rdata::ARdata;
55
use crate::message::rdata::cname_rdata::CnameRdata;
66
use crate::message::rdata::soa_rdata::SoaRdata;
77
use crate::message::rdata::aaaa_rdata::AAAARdata;
8-
use crate::message::rdata::Rdata;
8+
use crate::message::rdata::{self, Rdata};
99
use crate::message::rdata::txt_rdata::TxtRdata;
1010
use crate::message::rdata::mx_rdata::MxRdata;
1111
use crate::domain_name::DomainName;
1212
use crate::message::rdata::ptr_rdata::PtrRdata;
1313
use crate::message::resource_record::ResourceRecord;
1414
use crate::message::rclass::Rclass;
15+
use crate::message::rdata::ns_rdata::NsRdata;
1516
/*
1617
The following entries are defined:
1718
<blank>[<comment>]
@@ -160,13 +161,18 @@ impl DnsZone {
160161

161162
// Variables for the zone
162163
let mut name = String::new();
163-
let mut ttl = 3600; // Default value
164-
let mut soa: Option<SoaRdata> = None;
164+
let mut ttl = 3600; // Default value of ttl general
165+
let mut soa: SoaRdata = SoaRdata::new();
165166
let mut ns_records = Vec::new();
166167
let mut resource_records = Vec::new();
168+
//let class = "IN"; // Default value of class general, for the moment only IN is supported
167169

168-
// Variable to check multiples zones
169-
let mut origin_count = 0;
170+
// Variables to work with the file
171+
let mut last_name = String::new();
172+
let mut last_ttl = 3600;
173+
let mut class = Rclass::IN;
174+
let mut first_line = true;
175+
//let mut count_ns = 0;
170176

171177
// Read the file line by line
172178
for line in reader.lines() {
@@ -177,104 +183,171 @@ impl DnsZone {
177183
if line.is_empty() || line.starts_with(';') {
178184
continue;
179185
}
180-
181186
// Process directives
182187
if line.starts_with("$ORIGIN") {
183-
origin_count += 1;
184-
if origin_count > 1 {
185-
return Err(io::Error::new(
186-
io::ErrorKind::InvalidData,
187-
"Multiple $ORIGIN directives found",
188-
));
189-
}
190-
191188
name = line.split_whitespace().nth(1).unwrap_or("").to_string();
192189
continue;
193190
}
194191
if line.starts_with("$TTL") {
195192
ttl = line.split_whitespace().nth(1).unwrap_or("3600").parse().unwrap_or(3600);
196193
continue;
197194
}
198-
195+
// $INCLUDE directive is not supported
196+
199197
// Process records
200-
let parts: Vec<&str> = line.split_whitespace().collect();
201-
if parts.len() < 4 {
198+
let mut parts: Vec<&str> = line.split_whitespace().collect();
199+
200+
// Remove comments from the line
201+
if let Some(index) = parts.iter().position(|&x| x == ";") {
202+
parts.truncate(index);
203+
}
204+
205+
// Assume that the first line is the SOA record
206+
if first_line {
207+
parts.retain(|x| x != &"(" && x != &")");
208+
let record_name = parts[0]; // The first part is the name of the record
209+
let record_name_string = record_name.to_string(); // Convert to String
210+
name = record_name_string; // Save the name of the zone
211+
last_name = name.clone(); // Save the last name for the next iteration
212+
213+
// Set the SOA record
214+
soa.set_mname(DomainName::new_from_str(parts[3]));
215+
soa.set_rname(DomainName::new_from_str(parts[4]));
216+
soa.set_serial(parts[5].parse().unwrap_or(0));
217+
soa.set_refresh(parts[6].parse().unwrap_or(3600));
218+
soa.set_retry(parts.get(7).unwrap_or(&"1800").parse().unwrap_or(1800));
219+
soa.set_expire(parts.get(8).unwrap_or(&"1209600").parse().unwrap_or(1209600));
220+
soa.set_minimum(parts.get(9).unwrap_or(&"3600").parse().unwrap_or(3600));
221+
ttl = parts[9].parse().unwrap_or(3600); // Save the TTL for the next iteration
222+
// Change the flag to false
223+
first_line = false;
202224
continue;
203-
//return Err(io::Error::new(
204-
// io::ErrorKind::InvalidData,
205-
// "Registro de recurso incompleto",
206-
//));
207225
}
208226

209-
let record_name = parts[0];
210-
211-
let record_ttl_or_type = parts[1];
212-
213-
let rr_type_index = if record_ttl_or_type.parse::<u32>().is_ok() {
214-
ttl = record_ttl_or_type.parse().unwrap_or(3600);
215-
2
216-
} else {
217-
1
218-
};
219-
220-
let record_type = parts[rr_type_index];
221-
let record_class = parts[rr_type_index+1];
222-
match record_type {
223-
"SOA" => {
224-
if parts.len() >= 7 {
225-
// Crear un SoaRdata vacío y completarlo con setters
226-
let mut soa_data = SoaRdata::new();
227-
soa_data.set_mname(DomainName::new_from_str(parts[rr_type_index+2]));
228-
soa_data.set_rname(DomainName::new_from_str(parts[rr_type_index+3]));
229-
soa_data.set_serial(parts[rr_type_index+4].parse().unwrap_or(0));
230-
soa_data.set_refresh(parts[rr_type_index+5].parse().unwrap_or(3600));
231-
soa_data.set_retry(parts.get(rr_type_index+6).unwrap_or(&"1800").parse().unwrap_or(1800));
232-
soa_data.set_expire(parts.get(rr_type_index+7).unwrap_or(&"1209600").parse().unwrap_or(1209600));
233-
soa_data.set_minimum(parts.get(rr_type_index+8).unwrap_or(&"3600").parse().unwrap_or(3600));
234-
soa = Some(soa_data);
227+
// Check if the line has at least 4 parts
228+
if parts.len() >= 4 {
229+
let record_name = parts[0]; // The first part is the name of the record
230+
let record_name_string = record_name.to_string(); // Convert to String
231+
last_name = record_name_string; // Save the last name for the next iteration
232+
233+
let record_ttl_or_type = parts[1]; // The second part is the TTL or the record type
234+
235+
let mut record_ttl = ttl; // Default value of ttl for the record
236+
237+
let rr_type_index = if record_ttl_or_type.parse::<u32>().is_ok() { // Check if the second part is a TTL
238+
record_ttl = record_ttl_or_type.parse().unwrap_or(3600); // If it is a TTL, save it
239+
2 // The index of the record type is 3
240+
} else { // If it is not a TTL, it is the record type
241+
1 // The index of the record type is 2
242+
};
243+
244+
last_ttl = record_ttl; // Save the last ttl for the next iteration
245+
246+
let record_type = parts[rr_type_index]; // The third part is the record type
247+
match record_type {
248+
"NS" => { // If the record type is NS
249+
ns_records.push(parts[rr_type_index+1].to_string()); // Save the NS record
235250
}
251+
"A" => {
252+
let resource_record = ARdata::rr_from_master_file(parts[rr_type_index+1].split_whitespace(), ttl, "IN", record_name.to_string());
253+
resource_records.push(resource_record);
254+
}
255+
"AAAA" | "CNAME" | "MX" | "TXT" | "PTR" => {
256+
let rdata = match record_type {
257+
"AAAA" => {
258+
let ip_addr: std::net::IpAddr = parts[rr_type_index+1].parse().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid IP address"))?;
259+
Rdata::AAAA(AAAARdata::new_from_addr(ip_addr))
260+
},
261+
"CNAME" => {
262+
let cname = DomainName::new_from_str(parts[rr_type_index+1]);
263+
let mut cname_rdata = CnameRdata::new();
264+
cname_rdata.set_cname(cname);
265+
let rdata = Rdata::CNAME(cname_rdata);
266+
rdata}, // CNAME
267+
"MX" => Rdata::MX(MxRdata::new()),
268+
"TXT" => Rdata::TXT(TxtRdata::new(vec![parts[rr_type_index+1].to_string()])),
269+
"PTR" => Rdata::PTR(PtrRdata::new()),
270+
_ => continue,
271+
};
272+
273+
let mut resource_record = ResourceRecord::new(rdata);
274+
275+
resource_record.set_name(DomainName::new_from_str(record_name));
276+
resource_record.set_ttl(last_ttl);
277+
278+
resource_records.push(resource_record);
279+
}
280+
_ => {
281+
continue;
282+
} // Here is where ZONEMD and other unknow types should be entered.
236283
}
237-
"NS" => {
238-
ns_records.push(parts[rr_type_index+1].to_string());
239-
}
240-
"A" => {
241-
let resource_record = ARdata::rr_from_master_file(parts[rr_type_index+1].split_whitespace(), ttl, record_class, record_name.to_string());
242-
resource_records.push(resource_record);
243-
}
244-
"AAAA" | "CNAME" | "MX" | "TXT" | "PTR" => {
245-
let rdata = match record_type {
246-
"AAAA" => {
247-
let ip_addr: std::net::IpAddr = parts[rr_type_index+1].parse().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid IP address"))?;
248-
Rdata::AAAA(AAAARdata::new_from_addr(ip_addr))
249-
},
250-
"CNAME" => Rdata::CNAME(CnameRdata::new()), // CNAME
251-
"MX" => Rdata::MX(MxRdata::new()),
252-
"TXT" => Rdata::TXT(TxtRdata::new(vec![parts[rr_type_index+1].to_string()])),
253-
"PTR" => Rdata::PTR(PtrRdata::new()),
254-
_ => continue,
255-
};
256-
257-
let mut resource_record = ResourceRecord::new(rdata);
258-
259-
resource_record.set_name(DomainName::new_from_str(record_name));
260-
resource_record.set_ttl(ttl);
261-
262-
resource_records.push(resource_record);
284+
}
285+
else if parts.len() < 4 {
286+
//print!("{:?}", parts);
287+
288+
let record_ttl_or_type = parts[0];
289+
290+
let mut record_ttl = ttl; // Default value of ttl for the record
291+
292+
let rr_type_index = if record_ttl_or_type.parse::<u32>().is_ok() { // Check if the second part is a TTL
293+
record_ttl = record_ttl_or_type.parse().unwrap_or(3600); // If it is a TTL, save it
294+
1 // The index of the record type is 2
295+
} else { // If it is not a TTL, it is the record type
296+
0 // The index of the record type is 1
297+
};
298+
299+
300+
let record_type = parts[rr_type_index];
301+
let record_data = parts[rr_type_index+1];
302+
303+
match record_type {
304+
"NS" => {
305+
ns_records.push(record_data.to_string());
306+
}
307+
"A" => {
308+
let resource_record = ARdata::rr_from_master_file(record_data.split_whitespace(), ttl, "IN", last_name.to_string());
309+
resource_records.push(resource_record);
310+
}
311+
"AAAA" | "CNAME" | "MX" | "TXT" | "PTR" => {
312+
let rdata = match record_type {
313+
"AAAA" => {
314+
let ip_addr: std::net::IpAddr = record_data.parse().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid IP address"))?;
315+
Rdata::AAAA(AAAARdata::new_from_addr(ip_addr))
316+
},
317+
"CNAME" => {
318+
let cname = DomainName::new_from_str(record_data);
319+
let mut cname_rdata = CnameRdata::new();
320+
cname_rdata.set_cname(cname);
321+
let rdata = Rdata::CNAME(cname_rdata);
322+
rdata}, // CNAME
323+
"MX" => Rdata::MX(MxRdata::new()),
324+
"TXT" => Rdata::TXT(TxtRdata::new(vec![record_data.to_string()])),
325+
"PTR" => Rdata::PTR(PtrRdata::new()),
326+
_ => continue,
327+
};
328+
329+
let mut resource_record = ResourceRecord::new(rdata);
330+
331+
resource_record.set_name(DomainName::new_from_str(last_name.as_str()));
332+
resource_record.set_ttl(record_ttl);
333+
334+
resource_records.push(resource_record);
335+
}
336+
_ => {
337+
continue;
338+
}
263339
}
264-
_ => {
265-
continue;
266-
/*return Err(io::Error::new(
267-
io::ErrorKind::InvalidData,
268-
format!("Registro de recurso desconocido: {}", record_type),
269-
));*/
270-
} // Here is where ZONEMD and other unknow types should be entered.
271340
}
341+
/*else if parts.len() == 1 { // It is the case of the information of the SOA record
342+
continue;;
343+
} */
272344
}
273-
// Validate and construct the zone
345+
print!("{:?}", resource_records);
346+
// Validate and construct the zone
274347
Ok(DnsZone {
275348
name,
276349
ttl,
277-
soa: soa.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "SOA record missing"))?,
350+
soa,
278351
ns_records,
279352
resource_records,
280353
})
@@ -399,8 +472,8 @@ mod dns_zone_tests {
399472
let dns_zone = DnsZone::from_master_file(masterfile_path).unwrap();
400473

401474
// Validate main properties of the zone
402-
assert_eq!(dns_zone.name, "EDU.");
403-
assert_eq!(dns_zone.ttl, 86400); // Default TTL in the file
475+
assert_eq!(dns_zone.name, "EDU."); // The example does not have a line with $ORIGIN
476+
assert_eq!(dns_zone.ttl, 3600); // Default TTL in the file is 3600, the example does not have a line with $TTL
404477
assert_eq!(dns_zone.soa.get_mname().get_name(), "SRI-NIC.ARPA.");
405478
assert_eq!(dns_zone.soa.get_rname().get_name(), "HOSTMASTER.SRI-NIC.ARPA.");
406479
assert_eq!(dns_zone.soa.get_serial(), 870729);
@@ -410,14 +483,14 @@ mod dns_zone_tests {
410483
assert_eq!(dns_zone.soa.get_minimum(), 86400);
411484

412485
// Validate name server records
413-
assert_eq!(dns_zone.get_ns_records().len(), 2);
486+
assert_eq!(dns_zone.get_ns_records().len(), 13);
414487
assert!(dns_zone.get_ns_records().contains(&"SRI-NIC.ARPA.".to_string()));
415488
assert!(dns_zone.get_ns_records().contains(&"C.ISI.EDU.".to_string()));
416489

417490
// Validate resource records
418-
assert_eq!(dns_zone.get_resource_records().len(), 14); // Count A, NS, etc. records
491+
assert_eq!(dns_zone.get_resource_records().len(), 11); // Count A, NS, etc. records
419492
assert!(dns_zone.get_resource_records().iter().any(|rr| rr.get_name().get_name() == "ICS.UCI" && matches!(rr.get_rdata(), Rdata::A(_))));
420-
assert!(dns_zone.get_resource_records().iter().any(|rr| rr.get_name().get_name() == "YALE.EDU." && matches!(rr.get_rdata(), Rdata::NS(_))));
493+
//assert!(dns_zone.get_resource_records().iter().any(|rr| rr.get_name().get_name() == "YALE.EDU." && matches!(rr.get_rdata(), Rdata::NS(_))));
421494
}
422495

423496
#[test]
@@ -443,13 +516,13 @@ mod dns_zone_tests {
443516
assert_eq!(dns_zone.soa.get_minimum(), 86400);
444517

445518
// Validate name server records
446-
assert_eq!(dns_zone.ns_records.len(), 3);
519+
assert_eq!(dns_zone.ns_records.len(), 7);
447520
assert!(dns_zone.get_ns_records().contains(&"A.ISI.EDU.".to_string()));
448521
assert!(dns_zone.get_ns_records().contains(&"C.ISI.EDU.".to_string()));
449522
assert!(dns_zone.get_ns_records().contains(&"SRI-NIC.ARPA.".to_string()));
450523

451524
// Validate resource records
452-
assert_eq!(dns_zone.get_resource_records().len(), 14); // Count A, MX, HINFO, etc. records
525+
assert_eq!(dns_zone.get_resource_records().len(), 15); // Count A, MX, HINFO, etc. records
453526
assert!(dns_zone.get_resource_records().iter().any(|rr| rr.get_name().get_name() == "MIL." && matches!(rr.get_rdata(), Rdata::NS(_))));
454527
assert!(dns_zone.get_resource_records().iter().any(|rr| rr.get_name().get_name() == "A.ISI.EDU" && matches!(rr.get_rdata(), Rdata::A(_))));
455528
}

0 commit comments

Comments
 (0)