mirror of
https://github.com/ZeusWPI/ZNS.git
synced 2024-11-22 05:41:11 +01:00
add README and fix some todos
This commit is contained in:
parent
271ee5e395
commit
c1ab0cc953
4 changed files with 94 additions and 7 deletions
83
README.md
Normal file
83
README.md
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# Zeus (Domain) Name Server
|
||||||
|
|
||||||
|
Is implementation of an authoritative DNS server.
|
||||||
|
|
||||||
|
It gives all users who have a [Zauth](https://zauth.zeus.gent) account an own domain: `username.users.zeus.gent`.
|
||||||
|
|
||||||
|
## General Information
|
||||||
|
|
||||||
|
Creating/Updating your DNS records is only possible using dynamic DNS updating (DDNS, rfc2136).
|
||||||
|
It's an extension of DNS that lets you update your DNS records using the DNS protocol.
|
||||||
|
|
||||||
|
ZNS authenticates these update requests using SIG(0) (rfc2931).
|
||||||
|
This is another extension of DNS that defines a signature record. It is appended to the query and contains the signature of the original query and
|
||||||
|
some other information like expiration time to prevent replay attacks.
|
||||||
|
|
||||||
|
The signature is created with the private key of the signer and validated on the server with the corresponding public key.
|
||||||
|
ZNS has 2 methods of validating the signature:
|
||||||
|
- Using your SSH Keys in [Zauth](https://zauth.zeus.gent)
|
||||||
|
- Using a [DNSKEY record](https://datatracker.ietf.org/doc/html/rfc4034#section-2)
|
||||||
|
|
||||||
|
|
||||||
|
## User Guide
|
||||||
|
|
||||||
|
How to add an `A` record to `<your zauth username>.users.zeus.gent`.
|
||||||
|
|
||||||
|
### Step 1
|
||||||
|
|
||||||
|
Create an SSH key pair (or use an existing one). Currently, only ED25519 and RSA SSH key types are supported.
|
||||||
|
Add the public key to your Zauth account.
|
||||||
|
|
||||||
|
### Step 2
|
||||||
|
|
||||||
|
The (most) painless way for sending DNS update queries is using the `nsupdate` program.
|
||||||
|
With `nsupdate -k keys`, you can pass it your keys. But `nsupdate` expects your keys to have a certain format, so it won't accept the OPENSSH private key format.
|
||||||
|
That's why there is a CLI (`zns-cli`) available that converts the OPENSSH private key format and creates `.key` and `.private` files corresponding with your public and private keys.
|
||||||
|
And with some more info like the update ZONE (`username.users.zeus.gent`), the signing algorithm (ED25519 or RSA), ...
|
||||||
|
|
||||||
|
Execute:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
zns-cli --key <path to private ssh key> --username <zauth username>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can run `nsupdate -k Kdns.private`.
|
||||||
|
|
||||||
|
```
|
||||||
|
> zone username.users.zeus.gent
|
||||||
|
> update add username.users.zeus.gent 300 A <ip address>
|
||||||
|
> send
|
||||||
|
```
|
||||||
|
|
||||||
|
This will add an A record to `username.users.zeus.gent`.
|
||||||
|
The message will be signed with the private key, and the server will try to validate by trying to find a valid public SSH key from your Zauth account. Matching the `username` given in the zone.
|
||||||
|
The default expiration time with `nsupdate` is 5 minutes.
|
||||||
|
|
||||||
|
That's it... not that hard, is it?
|
||||||
|
|
||||||
|
### Step 3 (Optional)
|
||||||
|
|
||||||
|
It is also possible to put your public key in a DNSKEY record instead of Zauth. In the previous step, `zns-cli` also generated a `.key` file.
|
||||||
|
This contains a DNSKEY resource record you can add to your zone using `nsupdate`. Now the signature can be validated directly using this record.
|
||||||
|
|
||||||
|
It's also possible to directly generate a DNSKEY record key pair using `dnssec-keygen`.
|
||||||
|
|
||||||
|
## Server Setup Guide
|
||||||
|
|
||||||
|
There are three crates available at the root of the repo.
|
||||||
|
|
||||||
|
`zns` is a library which is both used by `zns-cli` and `zns-daemon`.
|
||||||
|
`zns-daemon` is the server that handles DNS queries.
|
||||||
|
|
||||||
|
The following environment variables should be set (or stored in a `.env` file):
|
||||||
|
```
|
||||||
|
DATABASE_URL=postgres://zns@localhost/zns
|
||||||
|
ZAUTH_URL="https://zauth.zeus.gent"
|
||||||
|
ZONE="users.zeus.gent"
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional: `ZNS_ADDRESS` and `ZNS_PORT`.
|
||||||
|
|
||||||
|
After setting `DATABASE_URL`, create the database and run the migrations with `diesel migration run`.
|
||||||
|
|
||||||
|
It's quite possible that something is not conform to an RFC, creating an issue is appreciated.
|
|
@ -1,5 +1,5 @@
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
use num_bigint::{BigInt, BigUint};
|
use num_bigint::BigUint;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
|
@ -76,7 +76,7 @@ fn read_bytes(reader: &mut Reader) -> Result<Vec<u8>, ZNSError> {
|
||||||
|
|
||||||
impl KeyTransformer for Ed25519KeyPair {
|
impl KeyTransformer for Ed25519KeyPair {
|
||||||
fn from_openssh(reader: &mut Reader) -> Result<Self, ZNSError> {
|
fn from_openssh(reader: &mut Reader) -> Result<Self, ZNSError> {
|
||||||
// public key parts
|
// public key parts//TODO: change to SIG
|
||||||
let length = reader.read_u32()?;
|
let length = reader.read_u32()?;
|
||||||
reader.read(length as usize)?;
|
reader.read(length as usize)?;
|
||||||
|
|
||||||
|
@ -259,6 +259,7 @@ impl KeyTransformer for OpenSSHKey {
|
||||||
|
|
||||||
const OPENSSH_START: &str = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
const OPENSSH_START: &str = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
||||||
const OPENSSH_END: &str = "-----END OPENSSH PRIVATE KEY-----";
|
const OPENSSH_END: &str = "-----END OPENSSH PRIVATE KEY-----";
|
||||||
|
const FILENAME: &str = "Kdns";
|
||||||
|
|
||||||
fn ssh_to_dnskey(file_content: &str, username: &str) -> Result<(), Box<dyn Error>> {
|
fn ssh_to_dnskey(file_content: &str, username: &str) -> Result<(), Box<dyn Error>> {
|
||||||
if !file_content.starts_with(OPENSSH_START) || !file_content.ends_with(OPENSSH_END) {
|
if !file_content.starts_with(OPENSSH_START) || !file_content.ends_with(OPENSSH_END) {
|
||||||
|
@ -277,8 +278,8 @@ fn ssh_to_dnskey(file_content: &str, username: &str) -> Result<(), Box<dyn Error
|
||||||
let mut reader = Reader::new(&bin);
|
let mut reader = Reader::new(&bin);
|
||||||
let key = OpenSSHKey::from_openssh(&mut reader)?;
|
let key = OpenSSHKey::from_openssh(&mut reader)?;
|
||||||
|
|
||||||
let mut file_private = File::create("Kdns.private")?;
|
let mut file_private = File::create(format!("{}.private", FILENAME))?;
|
||||||
let mut file_public = File::create("Kdns.key")?;
|
let mut file_public = File::create(format!("{}.key", FILENAME))?;
|
||||||
|
|
||||||
let (private, public) = key.to_dnskey(username);
|
let (private, public) = key.to_dnskey(username);
|
||||||
file_private.write(private.as_bytes())?;
|
file_private.write(private.as_bytes())?;
|
||||||
|
@ -292,7 +293,10 @@ fn main() {
|
||||||
|
|
||||||
match fs::read_to_string(args.key) {
|
match fs::read_to_string(args.key) {
|
||||||
Ok(contents) => match ssh_to_dnskey(contents.trim(), &args.username) {
|
Ok(contents) => match ssh_to_dnskey(contents.trim(), &args.username) {
|
||||||
Ok(()) => println!("Success"),
|
Ok(()) => println!(
|
||||||
|
"Successfully written {}.private and {}.key",
|
||||||
|
FILENAME, FILENAME
|
||||||
|
),
|
||||||
Err(error) => eprintln!("{}", error),
|
Err(error) => eprintln!("{}", error),
|
||||||
},
|
},
|
||||||
Err(error) => eprintln!("{}", error),
|
Err(error) => eprintln!("{}", error),
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl ResponseHandler for UpdateHandler {
|
||||||
|
|
||||||
//TODO: this code is ugly
|
//TODO: this code is ugly
|
||||||
let last = message.additional.last();
|
let last = message.additional.last();
|
||||||
if last.is_some() && last.unwrap()._type == Type::Type(RRType::KEY) {
|
if last.is_some() && last.unwrap()._type == Type::Type(RRType::SIG) {
|
||||||
let sig = Sig::new(last.unwrap(), raw)?;
|
let sig = Sig::new(last.unwrap(), raw)?;
|
||||||
|
|
||||||
if !authenticate::authenticate(&sig, &zone.qname, connection)
|
if !authenticate::authenticate(&sig, &zone.qname, connection)
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub enum Type {
|
||||||
pub enum RRType {
|
pub enum RRType {
|
||||||
A = 1,
|
A = 1,
|
||||||
SOA = 6,
|
SOA = 6,
|
||||||
KEY = 24, //TODO: change to SIG
|
SIG = 24,
|
||||||
DNSKEY = 48,
|
DNSKEY = 48,
|
||||||
OPT = 41,
|
OPT = 41,
|
||||||
ANY = 255,
|
ANY = 255,
|
||||||
|
|
Loading…
Reference in a new issue