Giter Club home page Giter Club logo

csharp-dns-server's Introduction

csharp-dns-server

Fully functional DNS server written in C#.

The project was conceived while working to reduce the cost of datacentre "stamps" while providing robust services within a datacentre, specifically to remove the need for an expensive load-balancer device by providing round-robin DNS services, and retrying connectivity instead.

Licence

This software is licenced under MIT terms that permits reuse within proprietary software provided all copies of the licensed software include a copy of the MIT License terms and the copyright notice. See licence.txt

Getting Started

// clone the repo
>> cd $repo-root
>> git clone https://github.com/stephbu/csharp-dns-server

// check you can build the project
>> cd $repo-root/csharp-dns-server
>> dotnet build

// check that the tests run
>> dotnet test

Gotchas

  • if you're running on Windows 10 with Docker Tools installed, Docker uses the ICS SharedAccess service to provide DNS resolution for Docker containers - this listens on UDP:53, and will conflict with the DNS project. Either turn off the the service (net stop SharedAccess), or change the UDP port.

Features

As written, the server has the following features:

  • Pluggable Zone Resolver. Host one or more zones locally, and run your code to resolve names in that zone. Enables many complex scenarios such as:
  • round-robin load-balancing. Distribute load and provide failover with a datacentre without expensive hardware.
  • health-checks. While maintaining a list of machines in round-robin for a name, the code performs periodic healthchecks against the machines, if necessary removing machines that fail the health checks from rotation.
  • Delegates all other DNS lookup to host machines default DNS server(s)

The DNS server has a built-in Web Server providing operational insight into the current server behaviour.

  • healthcheck for server status
  • counters
  • zone information

Interesting Possible Uses

Time-based constraints such as parental controls to block a site, e.g. Facebook. Logging of site usage e.g. company notifications

Challenges

Testing

Two phases of testing was completed.

  1. Verification that the bit-packing classes correctly added and removed bits in correct Endian order, complicated by network bitpacking in reverse order to Windows big-endian packing.

  2. Protocol verification - that well known messages were correctly decoded and re-encoded using the bit-packing system.

Much time was spent using Netmon to capture real DNS challenges and verify that the C# DNS server responded appropriately.

DNS-Sec

No effort made to handle or respond to DNS-Sec challenges.

Contribution Guide

Pull Requests, Bug Reports, and Feature Requests are most welcome.

Contribution Workflow

Suggested workflow for PRs is

  1. Make a fork of csharp-dns-server/master in your own repository.
  2. Create a branch in your own repo to entirely encapsulate all your proposed changes
  3. Make your changes, add documentation if you need it, markdown text preferred.
  4. Squash your commits into a single change (Find out how to squash here)
  5. Submit a PR, and put in comments anything that you think I'll need to help merge and evaluate the changes

Licence Reminder

All contributions must be licenced under the same MIT terms, do include a header file to that effect.

csharp-dns-server's People

Contributors

lordzomat avatar stephbu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

csharp-dns-server's Issues

Implement DNS Caching

Goal: cache responses from upstream servers respecting TTL
Complete port of System.Runtime.Caching to .NET Core 2.2, test and integrate.

xUnit Test Hosting

Replace VS test frameworks with xUnit to enable cross platform build verification

Pluggable Healthcheck Provider

Current the health check system uses HTTP on a well-known port, with a well-known URL to check for server status. This work item would change this into a configureable and pluggable pass/fail protocol.

Error in the compressed string pointer parsing

Specifically in line 63 of the DnsProtocol class (ReadString method). According to the RFC1035 when you encounter a pointer (denoted through the top two bits set to 1) the lower remaining 6 bytes should form a 14 bit offset with the next octet. Currently you ignore the remaining 6 bits and just read the next byte as offset. That byte does represent the lower 8 bits of the offset and would work as long as you don't encounter any offset to a position greater than 255

Specifically this line:
currentOffset = bytes[currentOffset];

Should read

currentOffset = bytes[currentOffset] | (segmentLength & 0x3F)<<8;

So we simply add the 6 bits of the first byte as the high order bits of the second byte to get our 14 bit offset.

Of course for UDP requests we are limited to 512 octets. So we would need at max the lowest additional bit from those 6 bits. However TCP requests could be longer

HttpServer

The method Start when the HttpServer is enabled isn't invoked.

Adding _listener.Start() there is an exception, because the URI must be registered using netsh in the Windows platform.

netsh http add urlacl url=http://+:8080/ user=BUILTIN\Users

Race condition in parsing the dns message

I detected a race condition in your parsing logic of the dns messages.

You pass the SocketAsyncEventArgs object directly to the method OnRequest which will be processed in a new thread.

SocketAsyncEventArgs args = new SocketAsyncEventArgs();

var process = Task.Run(() => OnRequest(args));

Right before or during the processing happens another DNS message could be received which will change the content of the buffer inside the SocketAsyncEventArgs so the already running thread parsing the first message will likely see parts of the new message if it's not done yet.

This happened in my case, where my linux device send two requests in parallel one "IN A" and "IN AAAA". The first message received was the "IN A" request but right before the parser came to the point to read the type of the request the second message changed the buffer and the type was read as "AAAA".

You should consider to copy the content of the received data to a new buffer and pass that to your parser for example like so:

if (OnRequest != null)
{
	var buffer = new byte[bytesRead];
	Buffer.BlockCopy(args.Buffer, 0, buffer, 0, buffer.Length);
	var process = Task.Run(() => OnRequest(args, buffer));
}

This ensures that each thread has it's own data and that args.Buffer is not accessed in parallel from multiple threads at the same time.

Regardless of this issue, your DNS server helped my to diagnose a little issue on my linux device. I used it to check which exact requests are send. Thanks for the great work!

Configuration Provider

Pluggable configuration provider that can fetch from non-file sources e.g. HTTP and Git.

There is no "d:\" on linux

$ mono Dns.exe 

Unhandled Exception:
System.IO.FileNotFoundException: filename not found
File name: '/var/calculate/remote/distfiles/egit-src/csharp-dns-server.git/Dns/bin/Debug/d:\data\machineinfo.csv'
  at Dns.ZoneProvider.FileWatcherZoneProvider..ctor (System.String filename) <0x40ca25d0 + 0x00bef> in :0 
  at Dns.ZoneProvider.AP.APZoneProvider..ctor (System.String machineInfoFile, System.String zoneSuffix) <0x40ca24a0 + 0x0001f> in :0 
  at Dns.Program.Main (System.String[] args) <0x40c7a8b0 + 0x000c7> in :0 
[ERROR] FATAL UNHANDLED EXCEPTION: Nested exception trying to figure out what went wrong

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.