create trait for dns server interactions
This commit is contained in:
parent
befed6a38b
commit
247f72871e
5 changed files with 82 additions and 32 deletions
24
src/dns/api.rs
Normal file
24
src/dns/api.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use crate::dns;
|
||||||
|
|
||||||
|
// TODO: Use model types instead of dns types as input / output and only convert internaly?
|
||||||
|
|
||||||
|
// Zone content api
|
||||||
|
// E.g.: DNS update + axfr, zone file read + write
|
||||||
|
#[async_trait]
|
||||||
|
pub trait RecordApi {
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
async fn get_records(&mut self, zone: dns::Name, class: dns::DNSClass) -> Result<Vec<dns::Record>, Self::Error>;
|
||||||
|
async fn add_records(&mut self, zone: dns::Name, class: dns::DNSClass, new_records: Vec<dns::Record>) -> Result<(), Self::Error>;
|
||||||
|
// update_records
|
||||||
|
// delete_records
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone management api, todo
|
||||||
|
// E.g.: Manage catalog zone, dynamically generate knot / bind / nsd config...
|
||||||
|
pub trait ZoneApi {
|
||||||
|
// get_zones
|
||||||
|
// add_zone
|
||||||
|
// delete_zone
|
||||||
|
// exists
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ use trust_dns_proto::error::ProtoError;
|
||||||
use trust_dns_proto::iocompat::AsyncIoTokioAsStd;
|
use trust_dns_proto::iocompat::AsyncIoTokioAsStd;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use super::message::DnsMessage;
|
|
||||||
|
|
||||||
|
|
||||||
pub struct DnsClient(AsyncClient);
|
pub struct DnsClient(AsyncClient);
|
||||||
|
@ -27,8 +27,6 @@ impl DerefMut for DnsClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DnsMessage for AsyncClient {}
|
|
||||||
|
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
impl<'r> FromRequest<'r> for DnsClient {
|
impl<'r> FromRequest<'r> for DnsClient {
|
||||||
|
|
|
@ -2,11 +2,11 @@ use trust_dns_proto::DnsHandle;
|
||||||
use trust_dns_client::rr::{DNSClass, RecordType};
|
use trust_dns_client::rr::{DNSClass, RecordType};
|
||||||
use trust_dns_client::op::{UpdateMessage, OpCode, MessageType, Message, Query, ResponseCode};
|
use trust_dns_client::op::{UpdateMessage, OpCode, MessageType, Message, Query, ResponseCode};
|
||||||
use trust_dns_client::error::ClientError;
|
use trust_dns_client::error::ClientError;
|
||||||
use trust_dns_proto::error::ProtoError;
|
|
||||||
use trust_dns_client::proto::xfer::{DnsRequestOptions};
|
use trust_dns_client::proto::xfer::{DnsRequestOptions};
|
||||||
|
|
||||||
use super::{Name, Record, RData};
|
use super::{Name, Record, RData};
|
||||||
use super::client::{ClientResponse};
|
use super::client::{ClientResponse, DnsClient};
|
||||||
|
use super::api::RecordApi;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -21,15 +21,29 @@ pub enum MessageError {
|
||||||
ResponceNotOk(ResponseCode)
|
ResponceNotOk(ResponseCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DnsApiClient {
|
||||||
|
client: DnsClient
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DnsApiClient {
|
||||||
|
pub fn new(client: DnsClient) -> Self {
|
||||||
|
DnsApiClient {
|
||||||
|
client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait DnsMessage: DnsHandle<Error = ProtoError> + Send {
|
impl RecordApi for DnsApiClient {
|
||||||
async fn get_records(&mut self, zone: Name, class: DNSClass) -> Result<Vec<Record>, MessageError>
|
type Error = MessageError;
|
||||||
|
|
||||||
|
async fn get_records(&mut self, zone: Name, class: DNSClass) -> Result<Vec<Record>, Self::Error>
|
||||||
{
|
{
|
||||||
let response = {
|
let response = {
|
||||||
let mut query = Query::query(zone, RecordType::AXFR);
|
let mut query = Query::query(zone, RecordType::AXFR);
|
||||||
query.set_query_class(class);
|
query.set_query_class(class);
|
||||||
ClientResponse(self.lookup(query, DnsRequestOptions::default())).await.map_err(|e| MessageError::ClientError(e))?
|
ClientResponse(self.client.lookup(query, DnsRequestOptions::default())).await.map_err(|e| MessageError::ClientError(e))?
|
||||||
};
|
};
|
||||||
|
|
||||||
if response.response_code() != ResponseCode::NoError {
|
if response.response_code() != ResponseCode::NoError {
|
||||||
|
@ -46,7 +60,7 @@ pub trait DnsMessage: DnsHandle<Error = ProtoError> + Send {
|
||||||
Ok(records)
|
Ok(records)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_records(&mut self, zone: Name, class: DNSClass, new_records: Vec<Record>) -> Result<ClientResponse<<Self as DnsHandle>::Response>, MessageError>
|
async fn add_records(&mut self, zone: Name, class: DNSClass, new_records: Vec<Record>) -> Result<(), Self::Error>
|
||||||
{
|
{
|
||||||
let mut mismatched_class = Vec::new();
|
let mut mismatched_class = Vec::new();
|
||||||
let mut mismatched_zone = Vec::new();
|
let mut mismatched_zone = Vec::new();
|
||||||
|
@ -90,6 +104,12 @@ pub trait DnsMessage: DnsHandle<Error = ProtoError> + Send {
|
||||||
edns.set_version(0);
|
edns.set_version(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(ClientResponse(self.send(message)));
|
let response = ClientResponse(self.client.send(message)).await.map_err(|e| MessageError::ClientError(e))?;
|
||||||
|
|
||||||
|
if response.response_code() != ResponseCode::NoError {
|
||||||
|
return Err(MessageError::ResponceNotOk(response.response_code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod message;
|
pub mod dns_api;
|
||||||
|
pub mod api;
|
||||||
|
|
||||||
// Reexport trust dns types for convenience
|
// Reexport trust dns types for convenience
|
||||||
pub use trust_dns_client::rr::rdata::{
|
pub use trust_dns_client::rr::rdata::{
|
||||||
|
@ -9,3 +10,6 @@ pub use trust_dns_client::rr::{
|
||||||
RData, DNSClass, Record
|
RData, DNSClass, Record
|
||||||
};
|
};
|
||||||
pub use trust_dns_proto::rr::Name;
|
pub use trust_dns_proto::rr::Name;
|
||||||
|
|
||||||
|
// Reexport module types
|
||||||
|
pub use api::{RecordApi, ZoneApi};
|
|
@ -11,14 +11,15 @@ use trust_dns_client::rr::{DNSClass, RecordType};
|
||||||
|
|
||||||
use crate::DbConn;
|
use crate::DbConn;
|
||||||
use crate::dns;
|
use crate::dns;
|
||||||
use crate::dns::message::DnsMessage;
|
use crate::dns::api::RecordApi;
|
||||||
use crate::dns::message::MessageError;
|
use crate::dns::dns_api::DnsApiClient;
|
||||||
|
use crate::dns::dns_api::MessageError;
|
||||||
use crate::models;
|
use crate::models;
|
||||||
|
|
||||||
|
|
||||||
#[get("/zones/<zone>/records")]
|
#[get("/zones/<zone>/records")]
|
||||||
pub async fn get_zone_records(
|
pub async fn get_zone_records(
|
||||||
mut client: dns::client::DnsClient,
|
client: dns::client::DnsClient,
|
||||||
conn: DbConn,
|
conn: DbConn,
|
||||||
user_info: Result<models::UserInfo, models::ErrorResponse>,
|
user_info: Result<models::UserInfo, models::ErrorResponse>,
|
||||||
zone: models::AbsoluteName
|
zone: models::AbsoluteName
|
||||||
|
@ -35,7 +36,9 @@ pub async fn get_zone_records(
|
||||||
}
|
}
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
let records: Vec<_> = match client.get_records(zone.clone(), DNSClass::IN).await {
|
let mut dns_api = DnsApiClient::new(client);
|
||||||
|
|
||||||
|
let records: Vec<_> = match dns_api.get_records(zone.clone(), DNSClass::IN).await {
|
||||||
Ok(records) => records.into_iter().map(models::Record::from).collect(),
|
Ok(records) => records.into_iter().map(models::Record::from).collect(),
|
||||||
|
|
||||||
Err(MessageError::ResponceNotOk(code)) => {
|
Err(MessageError::ResponceNotOk(code)) => {
|
||||||
|
@ -55,7 +58,7 @@ pub async fn get_zone_records(
|
||||||
|
|
||||||
#[post("/zones/<zone>/records", data = "<new_records>")]
|
#[post("/zones/<zone>/records", data = "<new_records>")]
|
||||||
pub async fn create_zone_records(
|
pub async fn create_zone_records(
|
||||||
mut client: dns::client::DnsClient,
|
client: dns::client::DnsClient,
|
||||||
conn: DbConn,
|
conn: DbConn,
|
||||||
user_info: Result<models::UserInfo, models::ErrorResponse>,
|
user_info: Result<models::UserInfo, models::ErrorResponse>,
|
||||||
zone: models::AbsoluteName,
|
zone: models::AbsoluteName,
|
||||||
|
@ -98,8 +101,13 @@ pub async fn create_zone_records(
|
||||||
).err();
|
).err();
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = match client.add_records(zone.clone(), DNSClass::IN, records) {
|
let mut dns_api = DnsApiClient::new(client);
|
||||||
Ok(query) => query.await.map_err(models::make_500)?,
|
|
||||||
|
match dns_api.add_records(zone.clone(), DNSClass::IN, records).await {
|
||||||
|
Ok(_) => {
|
||||||
|
return Ok(Json(()));
|
||||||
|
//query.await.map_err(models::make_500)?;
|
||||||
|
}
|
||||||
Err(MessageError::RecordNotInZone { zone, class, mismatched_class, mismatched_zone}) => {
|
Err(MessageError::RecordNotInZone { zone, class, mismatched_class, mismatched_zone}) => {
|
||||||
return models::ErrorResponse::new(
|
return models::ErrorResponse::new(
|
||||||
Status::BadRequest,
|
Status::BadRequest,
|
||||||
|
@ -113,21 +121,17 @@ pub async fn create_zone_records(
|
||||||
})
|
})
|
||||||
).err();
|
).err();
|
||||||
},
|
},
|
||||||
Err(e) => return models::make_500(e).err()
|
Err(MessageError::ResponceNotOk(code)) => {
|
||||||
};
|
println!("Update of zone {} failed with code {}", *zone, code);
|
||||||
|
|
||||||
// TODO: better error handling
|
|
||||||
if response.response_code() != ResponseCode::NoError {
|
|
||||||
println!("Update of zone {} failed with code {}", *zone, response.response_code());
|
|
||||||
return models::ErrorResponse::new(
|
return models::ErrorResponse::new(
|
||||||
Status::NotFound,
|
Status::NotFound,
|
||||||
"Update of zone failed".into()
|
"Update of zone failed".into()
|
||||||
).with_details(json!({
|
).with_details(json!({
|
||||||
"zone_name": zone.to_utf8()
|
"zone_name": zone.to_utf8()
|
||||||
})).err();
|
})).err();
|
||||||
}
|
},
|
||||||
|
Err(e) => return models::make_500(e).err()
|
||||||
Ok(Json(()))
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/zones")]
|
#[get("/zones")]
|
||||||
|
|
Loading…
Reference in a new issue