add basic record creation route

main
Hannaeko 2022-03-04 00:44:29 +01:00
parent 936addb624
commit b7db84e9a8
3 changed files with 60 additions and 20 deletions

View File

@ -18,7 +18,7 @@ use super::trust_dns_types::{self, Name};
use crate::config::Config; use crate::config::Config;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize, Clone)]
#[serde(tag = "Type")] #[serde(tag = "Type")]
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
pub enum RData { pub enum RData {
@ -101,6 +101,8 @@ pub enum RData {
data: String, data: String,
}, },
// ZERO, // ZERO,
// TODO: DS
} }
impl From<trust_dns_types::RData> for RData { impl From<trust_dns_types::RData> for RData {
@ -156,6 +158,7 @@ impl From<trust_dns_types::RData> for RData {
fingerprint: trust_dns_types::sshfp::HEX.encode(sshfp.fingerprint()), fingerprint: trust_dns_types::sshfp::HEX.encode(sshfp.fingerprint()),
}, },
//TODO: This might alter data if not utf8 compatible, probably need to be replaced //TODO: This might alter data if not utf8 compatible, probably need to be replaced
//TODO: check whether concatenating txt data is harmful or not
trust_dns_types::RData::TXT(txt) => RData::TXT { text: format!("{}", txt) }, trust_dns_types::RData::TXT(txt) => RData::TXT { text: format!("{}", txt) },
trust_dns_types::RData::DNSSEC(data) => RData::DNSSEC(data), trust_dns_types::RData::DNSSEC(data) => RData::DNSSEC(data),
rdata => { rdata => {
@ -284,7 +287,7 @@ impl<'a> fmt::Display for CAAValue<'a> {
} }
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize, Clone)]
pub enum DNSClass { pub enum DNSClass {
IN, IN,
CH, CH,
@ -340,7 +343,7 @@ where
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize, Clone)]
pub struct Record { pub struct Record {
#[serde(rename = "Name")] #[serde(rename = "Name")]
pub name: SerdeName, pub name: SerdeName,
@ -374,7 +377,7 @@ impl TryFrom<Record> for trust_dns_types::Record {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct SerdeName(Name); pub struct SerdeName(Name);
impl<'de> Deserialize<'de> for SerdeName { impl<'de> Deserialize<'de> for SerdeName {

View File

@ -24,7 +24,7 @@ use crate::models::errors::{ErrorResponse, make_500};
use crate::models::dns::AbsoluteName; use crate::models::dns::AbsoluteName;
const BEARER: &str = "Bearer "; const BEARER: &str = "Bearer ";
const AUTH_HEADER: &str = "Authentication"; const AUTH_HEADER: &str = "Authorization";
#[derive(Debug, DbEnum, Deserialize, Clone)] #[derive(Debug, DbEnum, Deserialize, Clone)]

View File

@ -1,13 +1,10 @@
use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use serde_json::json;
use rocket::Response; use rocket::Response;
use rocket::http::Status; use rocket::http::Status;
use rocket_contrib::json::Json; use rocket_contrib::json::Json;
use serde_json::json;
use trust_dns_client::{client::ClientHandle, op::UpdateMessage}; use trust_dns_client::{client::ClientHandle, op::UpdateMessage};
use trust_dns_client::op::ResponseCode; use trust_dns_client::op::ResponseCode;
use trust_dns_client::rr::{DNSClass, RecordType}; use trust_dns_client::rr::{DNSClass, RecordType};
@ -50,8 +47,10 @@ pub async fn get_zone_records(
println!("Querrying AXFR of zone {} failed with code {}", *zone, response.response_code()); println!("Querrying AXFR of zone {} failed with code {}", *zone, response.response_code());
return ErrorResponse::new( return ErrorResponse::new(
Status::NotFound, Status::NotFound,
format!("Zone {} could not be found", *zone) "Zone could not be found".into()
).err() ).with_details(json!({
"zone_name": zone.to_utf8()
})).err();
} }
let answers = response.answers(); let answers = response.answers();
@ -85,21 +84,46 @@ pub async fn create_zone_records(
user_info.get_zone(c, &zone_name) user_info.get_zone(c, &zone_name)
} }
}).await?; }).await?;
// TODO: What about relative names (also in cnames and stuff) // TODO: What about relative names (also in cnames and stuff)
// TODO: error handling let mut bad_records = Vec::new();
let records: Vec<trust_dns_types::Record> = new_records.into_inner().into_iter().map(|r| r.try_into().unwrap()).collect(); let mut records: Vec<trust_dns_types::Record> = Vec::new();
for record in new_records.into_inner().into_iter() {
let this_record = record.clone();
if let Ok(record) = record.try_into() {
records.push(record);
} else {
bad_records.push(this_record.clone());
}
}
let bad_zone_records: Vec<_> = records.iter().filter(|record| !zone.zone_of(record.name())).collect(); let bad_zone_records: Vec<_> = records.iter().filter(|record| !zone.zone_of(record.name())).collect();
// TODO: Get zone class from somewhere instead of always assuming IN // TODO: Get zone class from somewhere instead of always assuming IN
let bad_class_records: Vec<_> = records.iter().filter(|record| record.dns_class() != DNSClass::IN).collect(); let bad_class_records: Vec<_> = records.iter().filter(|record| record.dns_class() != DNSClass::IN).collect();
if !bad_records.is_empty() {
return ErrorResponse::new(
Status::BadRequest,
"Record list contains records that could not been parsed into DNS records".into()
).with_details(
json!({
"zone_name": zone.to_utf8(),
"records": bad_records
})
).err();
}
if !bad_zone_records.is_empty() { if !bad_zone_records.is_empty() {
return ErrorResponse::new( return ErrorResponse::new(
Status::BadRequest, Status::BadRequest,
format!("Record list contains records whose name that do not belong to the zone {}", *zone) "Record list contains records whose name does not belong to the zone".into()
).with_details( ).with_details(
json!(bad_zone_records.into_iter().map(|r| r.name().to_utf8()).collect::<Vec<_>>()) json!({
).err() "zone_name": zone.to_utf8(),
"records": bad_zone_records.into_iter().map(|r| r.clone().into()).collect::<Vec<dns::Record>>()
})
).err();
} }
if !bad_class_records.is_empty() { if !bad_class_records.is_empty() {
@ -107,8 +131,11 @@ pub async fn create_zone_records(
Status::BadRequest, Status::BadRequest,
"Record list contains records whose class differs from the zone class `IN`".into() "Record list contains records whose class differs from the zone class `IN`".into()
).with_details( ).with_details(
json!(bad_class_records.into_iter().map(|r| r.name().to_utf8()).collect::<Vec<_>>()) json!({
).err() "zone_name": zone.to_utf8(),
"records": bad_class_records.into_iter().map(|r| r.clone().into()).collect::<Vec<dns::Record>>()
})
).err();
} }
let mut zone_query = Query::new(); let mut zone_query = Query::new();
@ -132,12 +159,22 @@ pub async fn create_zone_records(
edns.set_version(0); edns.set_version(0);
} }
// TODO: check if NOERROR or something let response = {
let _response = {
let query = dns::ClientResponse(client.send(message)); let query = dns::ClientResponse(client.send(message));
query.await.map_err(make_500)? query.await.map_err(make_500)?
}; };
// TODO: better error handling
if response.response_code() != ResponseCode::NoError {
println!("Update of zone {} failed with code {}", *zone, response.response_code());
return ErrorResponse::new(
Status::NotFound,
"Update of zone failed".into()
).with_details(json!({
"zone_name": zone.to_utf8()
})).err();
}
Ok(Json(())) Ok(Json(()))
} }