Conversation
8bc69ea to
50ec209
Compare
50ec209 to
b87a3d4
Compare
b87a3d4 to
9bbe892
Compare
9bbe892 to
87a56cb
Compare
87a56cb to
1f03629
Compare
stalowyjez
left a comment
There was a problem hiding this comment.
I have mixed feeling for this PR, reducing dependencies is always nice, but it feels a bit like reinventing the wheel. We also have some code in libfirewall which does some DNS parsing, maybe we should create some public DNS helper crate for pnet which would address our needs?
| pub struct Soa { | ||
| mname: &'static str, | ||
| rname: &'static str, | ||
| serial: u32, | ||
| refresh: i32, | ||
| retry: i32, | ||
| expire: i32, | ||
| minimum: u32, |
There was a problem hiding this comment.
This struct feels more like ttl_to_nord_soa_bytes function with everything written 3 times instead of just once ^^'
There was a problem hiding this comment.
Could you elaborate a little bit more?
In essence I wanted all of it to be static, but we do have configurable TTL..
There was a problem hiding this comment.
I guess having a const array (created in compile time with come const stuff) and just changing the ttl byte would be fastest, but I guess sth like:
fn create_nord_soa_with_ttl(ttl: u32) -> Result<Vec<u8>, DnsBuildError> {
let mut bytes = Vec::new();
encode_name(&mut bytes, "mesh.nordsec.com.");
encode_name(&mut bytes, "support.nordsec.com.");
bytes.extend_from_slice(&2015082403.to_be_bytes());
bytes.extend_from_slice(&7200.to_be_bytes());
bytes.extend_from_slice([&self.retry.to_be_bytes()](i32::try_from(ttl).map_err(|_| DnsBuildError::SoaTtlOutOfRange)?));
bytes.extend_from_slice(&1209600.to_be_bytes());
bytes.extend_from_slice(&ttl);
bytes
}
makes sense here. But probably reusing https://docs.rs/domain/0.11.1/domain/rdata/rfc1035/struct.Soa.html#impl-Soa%3CN%3E would also be nice? This would add a dependency on domain, but I think it is also a nice option to use instead of pnet dns stuff?
There was a problem hiding this comment.
Ofc, we could add some comments, or wrap stuff in come constants to make it clearer
There was a problem hiding this comment.
I wanted to use domain in the beginning but was asked not to add any additional dependencies since we have pnet..
I'll try to see how can I make this part "nicer"
There was a problem hiding this comment.
Removed the struct and converted to create_nord_soa_bytes
stalowyjez
left a comment
There was a problem hiding this comment.
Looks good enough, +1
| /// Normalize the name, converting to lowercase and trimming trailing dot | ||
| pub fn normalize(name: &str) -> String { | ||
| name.trim().trim_end_matches('.').to_ascii_lowercase() | ||
| } |
There was a problem hiding this comment.
Hmm, do we need it as a separate function? And should it be public?
There was a problem hiding this comment.
It's necessary for populating or searching the local "nord" records zone.
| pub struct Soa { | ||
| mname: &'static str, | ||
| rname: &'static str, | ||
| serial: u32, | ||
| refresh: i32, | ||
| retry: i32, | ||
| expire: i32, | ||
| minimum: u32, |
There was a problem hiding this comment.
I guess having a const array (created in compile time with come const stuff) and just changing the ttl byte would be fastest, but I guess sth like:
fn create_nord_soa_with_ttl(ttl: u32) -> Result<Vec<u8>, DnsBuildError> {
let mut bytes = Vec::new();
encode_name(&mut bytes, "mesh.nordsec.com.");
encode_name(&mut bytes, "support.nordsec.com.");
bytes.extend_from_slice(&2015082403.to_be_bytes());
bytes.extend_from_slice(&7200.to_be_bytes());
bytes.extend_from_slice([&self.retry.to_be_bytes()](i32::try_from(ttl).map_err(|_| DnsBuildError::SoaTtlOutOfRange)?));
bytes.extend_from_slice(&1209600.to_be_bytes());
bytes.extend_from_slice(&ttl);
bytes
}
makes sense here. But probably reusing https://docs.rs/domain/0.11.1/domain/rdata/rfc1035/struct.Soa.html#impl-Soa%3CN%3E would also be nice? This would add a dependency on domain, but I think it is also a nice option to use instead of pnet dns stuff?
| pub struct Soa { | ||
| mname: &'static str, | ||
| rname: &'static str, | ||
| serial: u32, | ||
| refresh: i32, | ||
| retry: i32, | ||
| expire: i32, | ||
| minimum: u32, |
There was a problem hiding this comment.
Ofc, we could add some comments, or wrap stuff in come constants to make it clearer
I have the same feeling, and I'm also missing explanation why we want to "get rid of all hickory_server dependencies." |
And what if they are not? |
|
I feel like there should be our rfc that describes what behavior do we want from magic dns. |
ca5d7ae to
408a415
Compare
|
Please, remember to cleanup (squash?) commits. |
408a415 to
327fb7f
Compare
|
+1 |
327fb7f to
8c89718
Compare
|
Next time: It would be really nice to include ticket number in the branch name 🙏 🙏 🙏 |
|
|
||
| /// Normalize the name, converting to lowercase and trimming trailing dot | ||
| pub(crate) fn normalize_qname(name: &str) -> String { | ||
| name.trim().trim_end_matches('.').to_ascii_lowercase() |
There was a problem hiding this comment.
why the trailing dot trimming? 🤔 maybe it would be nice to operate with FQDNs?
There was a problem hiding this comment.
So that we can operate on domains with trailing dot and or without eg :test.nord and test.nord.
We either need to trim the trailing dot, or append the trailing dot if it's not present.
There was a problem hiding this comment.
Updated to operate on FQDNs with trailing dot
| /// Constant values for .nord SOA record | ||
| const SOA_MNAME: &str = "mesh.nordsec.com"; | ||
| const SOA_RNAME: &str = "support.nordsec.com"; | ||
| const SOA_SERIAL: u32 = 2015082403; |
There was a problem hiding this comment.
while maybe it is not the most important part, but we probably should bump the serial number.
| /// | ||
| /// Trailing dot is optional, it is ignored | ||
| fn encode_name(out: &mut Vec<u8>, name: &str) -> Result<(), DnsBuildError> { | ||
| let trimmed = name.trim_end_matches('.'); |
There was a problem hiding this comment.
I would recommend to operate on FQDNs internally always, this would not require us to trim the trailing '.' and would reduce the amount of domain representations to support.
| truncated: &mut bool, | ||
| record_count: &mut u16, | ||
| ) -> Result<(), DnsBuildError> { | ||
| let rr_len = DNS_HEADER_OFFSET + data.len(); |
There was a problem hiding this comment.
I believe this is incorrect constant being used. I mean, the value of it is correct, but it is coincidental, but my understanding was the this constnat is meant to represent for DNS packet header length, and here we are calculated fixed-data size for resource-record.
There was a problem hiding this comment.
Hmm yeah semantically you're right, though are both the same size. I will introduce a separate constant.
There was a problem hiding this comment.
Added a separate const
20db861 to
e68879a
Compare
This module incorporates: - a lightweight decoder, that converts DNS request bytes into a `DnsPacket<'_>`, and exposes a helper functions like `parse_dns_query_packet()`, `find_nord_query()` and `normalize_qname()` to simplify with the correct request handling. - A packet builder specific for the local resolver use case, that converts a `ResponseKind` enum into appropriate DNS response bytes.
e68879a to
b6c2f87
Compare
Problem
We want to get rid of all
hickory_serverdependencies, because it set's up a full blown DNS server, we maintain our own (outdated) fork of, and it was source of a lot of bugs.As a first step we need to decide if DNS requests are related to
.nordzone.If they are, they should handled by our local resolver, and we need to serve the response packet back.
If not, the request is forwarded and resolved by the upstream nameservers.
Solution
This module incorporates:
DnsPacket<'_>struct, and exposes a helper functions likeparse_dns_packet(),find_nord_query()andnormalize_qname()to simplify with the correct request handling.ResponseKindenum into appropriate DNS response bytes.☑️ Definition of Done checklist