2021-03-20 02:31:41 +00:00
|
|
|
#![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
|
|
|
|
#[macro_use] extern crate rocket;
|
2021-03-26 22:30:38 +00:00
|
|
|
#[macro_use] extern crate rocket_contrib;
|
|
|
|
#[macro_use] extern crate diesel;
|
|
|
|
|
2021-03-20 02:31:41 +00:00
|
|
|
use rocket::State;
|
2021-03-20 18:18:08 +00:00
|
|
|
use rocket::http::Status;
|
2021-03-26 22:30:38 +00:00
|
|
|
|
2021-03-20 02:31:41 +00:00
|
|
|
use rocket_contrib::json::Json;
|
2021-03-26 22:30:38 +00:00
|
|
|
use rocket_contrib::databases::diesel as rocket_diesel;
|
|
|
|
|
|
|
|
use diesel::prelude::*;
|
2021-03-20 02:31:41 +00:00
|
|
|
|
|
|
|
use trust_dns_client::client::{Client, SyncClient};
|
|
|
|
use trust_dns_client::tcp::TcpClientConnection;
|
2021-03-20 18:18:08 +00:00
|
|
|
use trust_dns_client::op::{DnsResponse, ResponseCode};
|
2021-03-20 20:10:11 +00:00
|
|
|
use trust_dns_client::rr::{DNSClass, Name, RecordType};
|
2021-03-20 02:31:41 +00:00
|
|
|
|
2021-03-20 18:18:08 +00:00
|
|
|
mod models;
|
2021-03-20 02:31:41 +00:00
|
|
|
mod config;
|
2021-03-26 22:30:38 +00:00
|
|
|
mod auth;
|
|
|
|
mod schema;
|
2021-03-20 02:31:41 +00:00
|
|
|
|
2021-03-20 18:18:08 +00:00
|
|
|
use models::errors::ErrorResponse;
|
2021-03-26 22:30:38 +00:00
|
|
|
use auth::routes::*;
|
|
|
|
|
2021-03-20 18:18:08 +00:00
|
|
|
|
2021-03-26 22:30:38 +00:00
|
|
|
#[database("db")]
|
|
|
|
pub struct DbConn(diesel::SqliteConnection);
|
2021-03-20 02:31:41 +00:00
|
|
|
|
|
|
|
#[get("/zones/<zone>/records")]
|
2021-03-20 20:10:11 +00:00
|
|
|
fn get_zone_records(client: State<SyncClient<TcpClientConnection>>, zone: String) -> Result<Json<Vec<models::dns::Record>>, ErrorResponse<()>> {
|
2021-03-20 02:31:41 +00:00
|
|
|
// TODO: Implement FromParam for Name
|
2021-03-20 18:18:08 +00:00
|
|
|
let name = Name::from_utf8(&zone).unwrap();
|
2021-03-20 02:31:41 +00:00
|
|
|
|
2021-03-20 06:08:55 +00:00
|
|
|
let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AXFR).unwrap();
|
2021-03-20 18:18:08 +00:00
|
|
|
|
|
|
|
if response.response_code() != ResponseCode::NoError {
|
|
|
|
return ErrorResponse::new(
|
|
|
|
Status::NotFound,
|
|
|
|
format!("zone {} could not be found", name.to_utf8())
|
|
|
|
).err()
|
|
|
|
}
|
|
|
|
|
2021-03-20 20:10:11 +00:00
|
|
|
let answers = response.answers();
|
2021-03-20 06:08:55 +00:00
|
|
|
let mut records: Vec<_> = answers.to_vec().into_iter()
|
2021-03-20 18:18:08 +00:00
|
|
|
.map(|record| models::dns::Record::from(record))
|
2021-03-20 06:08:55 +00:00
|
|
|
.filter(|record| match record.rdata {
|
2021-03-20 18:18:08 +00:00
|
|
|
models::dns::RData::NULL { .. } | models::dns::RData::DNSSEC(_) => false,
|
2021-03-20 06:08:55 +00:00
|
|
|
_ => true,
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
// AXFR response ends with SOA, we remove it so it is not doubled in the response.
|
|
|
|
records.pop();
|
2021-03-20 02:31:41 +00:00
|
|
|
|
2021-03-20 18:18:08 +00:00
|
|
|
Ok(Json(records))
|
2021-03-20 02:31:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let app_config = config::load("config.toml".into());
|
|
|
|
|
|
|
|
let conn = TcpClientConnection::new(app_config.dns_server.address).unwrap();
|
|
|
|
let client = SyncClient::new(conn);
|
|
|
|
|
|
|
|
rocket::ignite()
|
|
|
|
.manage(client)
|
2021-03-26 22:30:38 +00:00
|
|
|
.attach(DbConn::fairing())
|
|
|
|
.mount("/api/v1", routes![get_zone_records, create_auth_token]).launch();
|
2021-03-20 02:31:41 +00:00
|
|
|
}
|