GithubHelp home page GithubHelp logo

jmhertlein / comfydns Goto Github PK

View Code? Open in Web Editor NEW
8.0 2.0 0.0 6.73 MB

The world's most comfortable implementation of RFC 1035.

License: GNU Affero General Public License v3.0

Java 48.49% Dockerfile 1.06% Shell 0.79% Ruby 18.50% JavaScript 0.91% HTML 29.61% CSS 0.39% SCSS 0.25%

comfydns's Introduction

ComfyDNS

The world's most comfortable local DNS server.

ComfyDNS gives you a fully-standards-compliant DNS server with a simple, modern web UI. Pull a docker image, run the container, and visit the URL. It's that easy.

Features

  • Simple UI
  • Easy deployment - it's just a docker container
  • Featureful - ComfyDNS includes local DNS with custom internal TLDs, DNS-based ad blocking (supporting both pihole and dnsmasq-format blocklists), and query tracing to visualize DNS lookups.

Quickstart

docker pull comfydns/comfydns:latest

docker run -it --name comfydns \
  -v comfydns-data:/opt/comfydns/ \
  -p 53:53/tcp \
  -p 53:53/udp \
  -p 8080:3000/tcp \
  -e COMFYDNS_UI_PASSPHRASE=changeme \
  comfydns/comfydns:latest

Change “changeme” to be a simple passphrase of your choosing. You’ll use this to both create user accounts and recover your account if you forget your password.

Now visit http://localhost:8080/user/sign_up and create a login using the passphrase.

How is this different from PiHole?

PiHole is an ad-blocker that also supports local DNS. ComfyDNS is a local DNS server that also supports ad-blocking. It's a matter of different priorities.

Also, not that it matters, but ComfyDNS is a full implementation of a recursive resolver, while PiHole uses dnsmasq.

License

AGPLv3

comfydns's People

Contributors

jmhertlein avatar

Stargazers

 avatar Mark Thomson avatar Justin Kidd avatar Michael avatar Saiful Azfar Ramlee avatar Jannis R avatar Philip Peterson avatar Collin Van Dyck avatar

Watchers

 avatar  avatar

comfydns's Issues

improve mobile experience

There's some rough edges in the mobile UI/UX right now, for both the website and the resolver UI.

DB-based dns cache

I'm seeing old gen grow and settle down at about 50MB right now. I assume most of this is RRs in the cache.

500 when viewing weird traces

[5b46121c-63f0-483f-9991-16d2458c6282] ActionView::Template::Error (undefined method `split' for nil:NilClass):
[5b46121c-63f0-483f-9991-16d2458c6282]      6:             <%= DNS::VALUE_TO_RCODE[event_badge_list.event["result"]["header"]["rcode"]] %>
[5b46121c-63f0-483f-9991-16d2458c6282]      7:           </span>
[5b46121c-63f0-483f-9991-16d2458c6282]      8:         <% else %>
[5b46121c-63f0-483f-9991-16d2458c6282]      9:           <span class="badge rounded-pill bg-danger"><%= event_badge_list.event["error"]["type"].split(".")[-1] %></span>
[5b46121c-63f0-483f-9991-16d2458c6282]     10:         <% end %>
[5b46121c-63f0-483f-9991-16d2458c6282]     11:         <% when "UPSTREAM_QUERY_SENT" %>
[5b46121c-63f0-483f-9991-16d2458c6282]     12:           <span class="badge rounded-pill bg-secondary"><%= event_badge_list.event["destHostname"] %></span>
[5b46121c-63f0-483f-9991-16d2458c6282]
[5b46121c-63f0-483f-9991-16d2458c6282] app/views/qtrace/_event_badge_list.html.erb:9
[5b46121c-63f0-483f-9991-16d2458c6282] app/views/trace_events/_trace_event.html.erb:5
[5b46121c-63f0-483f-9991-16d2458c6282] app/views/qtrace/view.html.erb:9
[5b46121c-63f0-483f-9991-16d2458c6282] app/views/qtrace/view.html.erb:8

responding to non-existent PTR records is slow

2024-07-01T10:20:23.594-0500 INFO EventLogger - [EVENT]: {"eventType":"REQUEST_IN","eventTime":"2024-07-01T15:20:23.594129954Z","id":"61fbdd5d-69fa-487b-a97a-3334998745c5","class":"JavaNetUDPRequest","numQuestions":1,"questions":[{"qname":"189.1.168.192.in-addr.arpa","qtype":12,"qclass":1}]}
2024-07-01T10:20:23.594-0500 INFO InitialCheckingState - [Q] [192.168.1.173]: QNAME: 189.1.168.192.in-addr.arpa, QTYPE: PTR, QCLASS: IN | 61fbdd5d-69fa-487b-a97a-3334998745c5
2024-07-01T10:20:29.605-0500 INFO EventLogger - [EVENT]: {"eventType":"REQUEST_OUT","eventTime":"2024-07-01T15:20:29.605300268Z","id":"61fbdd5d-69fa-487b-a97a-3334998745c5","rCode":3}

ensure we handle ENT's correctly where records exist for a different rrtype or rrclass

https://www.ietf.org/rfc/rfc4592.txt

specifically this portion:

2.2.1.  An Example

   To illustrate what is meant by existence consider this complete zone:

      $ORIGIN example.
      example.                 3600 IN  SOA   <SOA RDATA>
      example.                 3600     NS    ns.example.com.
      example.                 3600     NS    ns.example.net.
      *.example.               3600     TXT   "this is a wildcard"
      *.example.               3600     MX    10 host1.example.
      sub.*.example.           3600     TXT   "this is not a wildcard"
      host1.example.           3600     A     192.0.2.1
      _ssh._tcp.host1.example. 3600     SRV   <SRV RDATA>
      _ssh._tcp.host2.example. 3600     SRV   <SRV RDATA>
      subdel.example.          3600     NS    ns.example.com.
      subdel.example.          3600     NS    ns.example.net.

   A look at the domain names in a tree structure is helpful:

                                  |
                  -------------example------------
                 /           /         \          \
                /           /           \          \
               /           /             \          \
              *          host1          host2      subdel
              |            |             |
              |            |             |
             sub         _tcp          _tcp
                           |             |
                           |             |
                         _ssh          _ssh

   The following responses would be synthesized from one of the
   wildcards in the zone:

      QNAME=host3.example. QTYPE=MX, QCLASS=IN
           the answer will be a "host3.example. IN MX ..."

      QNAME=host3.example. QTYPE=A, QCLASS=IN
           the answer will reflect "no error, but no data"
           because there is no A RR set at '*.example.'

Specifically I suspect we'll currently return NAME_ERROR for this example:

      QNAME=host3.example. QTYPE=A, QCLASS=IN
           the answer will reflect "no error, but no data"
           because there is no A RR set at '*.example.'

I think we might need to have the DBAuthorityRRSource pull back all types+classes so it can make this decision in app code. the return type might also need to be modified so it can represent the difference between "name not found" and "name found but no RR's matched search". Maybe it throws a NameError exception - except that I don't think that necessarily merits using an exception and it's probably not good to be generating a stack trace etc for something that's not really exceptional from the perspective of the program. So while I'm not hugely fond of the API that presents, the return type is probably the right place for this information to go.

add a "fix website" UI

basically, it's a box that you put a URL in and it strips it down to the domain, then clears all RR's for all subdomains up to (but excluding) the TLD.

Support AXFR and SOA

This will allow running a less-interesting DNS server like bind9 as a secondary nameserver. It doesn't really make sense to run 2 full comfydns installs and there's not a lot of point in running a resolver-only comfydns.

Support subdomains

I don't support subdomains, only TLD's. Let's fix that.

Need to remove constraint of "No dots" in TLD name creation, and stop calling them TLD's.

Also need to add a constraint of not dots in host records under (sub)domains

add a double-checking state + env var

I want to check more rigorously that the resolver is correct.

I should:

  1. consolidate all responses into a single "SendResponseState" that fires off the final response.
  2. add an option to, prior to that last state, fly a request to 8.8.8.8 to double check my answer against theirs

in the future maybe it can send mismatches to comfydns.com?

Tighten up max lengths allowed

I just read https://news.ycombinator.com/item?id=39255423 and I can't offhand recall exactly how I handle tcp truncation. I suspect I either throw an exception while converting the 2-octet length field or I silently overflow while converting a >16bit value.

Should double check the logic and tighten things up as needed.

comment captured:

That's an excellent question! When I was writing that I was pretty deep in DNS code and standards I think I just understood that as a rule of DNS. Or at the least, I believed I understood. Looking back a decade later I can't find any standard which supports my statement. However lots of other secondary sources seem to agree with me.
"In these situations, the client needs to re-transmit over TCP for which the size limit is 64000 bytes" [0]
"The first response via UDP is, no surprise, truncated, so we retry via TCP. But now the DNS result delivered via TCP is also truncated! That is, the DNS server has determined that the result will not fit into the maximum response size. Why is that?
"Our payload is 4096 * 16 = 65536 bytes RDATA, which should fit into the DNS packet, which uses a two byte RDLENGTH field. But we also need to again account for the overhead noted above: 12 bytes DNS header, 36 bytes for the query, 11 bytes additional records, and 16 bytes for each A record, yielding (4096 * 16) + 12 + 36 + 11 = 65595 bytes in total. And the maximum size of an IP packet is 16 bit (via the IPv4 total length / IPv6 payload length). And that is now our limiting factor: 65536 bytes for DNS overhead + payload."
My best guess is that DNS just makes the assumption that everything needs to fit in a single IP packet and it doesn't care if it is UDP or TCP.
It is worth investigating if you have spare time.
[0]: https://www.infoblox.com/dns-security-resource-center/dns-se...
[1]: https://www.netmeister.org/blog/dns-size.htm

Add a Query Trace page and functionality

it's annoying to debug resolver/cache problems in text logs. so it's time to leverage TECHNOLOGY

I want to add a /trace page that has a text field. You type a query into the text field and submit it. CDNS then resolves the query but retains a bunch of query execution logging data for that query chain. The page then loads that and displays it in a very nice and easy to follow way.

Stretch goal: also run the same query with a totally clean cache. and be able to flip between the two to diff them.

Technical design:

there's a new task type, TRACE_TASK. the web UI creates one when you submit the text field.

there's a new DB table, trace_log, which will hold these long-term (and be deletable from the UI). some sub table, trade_log_entry will hold the individual parts.

The resolver will probably need to support some kind of observer pattern for the resolution steps.... I need to think more about that.

Remove the concept of multiple comfydns resolver servers

There can be only one.

Joking aside, there's no need to ever have more than one comfydns resolver.

When I implemented this feature, I was imagining that you would potentially run:

  • a database server
  • a primary cdns resolver
  • a secondary cdns resolver
  • the web UI

all on separate hosts. And you might want to stage DNS changes, deploy them to the primary, and then potentially either roll back or fail over to the secondary. And obviously you want the secondary in case hardware fails on the primary or something.

I think a better setup would be:

  • a db server
  • a primary cdns server
  • a secondary bind9 running as a dummy that only zone transfers your zones from the cdns resolver (since cdns supports AXFR)
  • the web UI

Or more normally:

  • cdns in a box
  • a secondary bind9-transfer-only server as above

So in both scenarios it seems like it's just better to have one comfydns resolver and have the secondary be a resolver that isn't dependent on a relational database.

Iron out multi-question queries

The happy path for multi-question queries is OK, but generally I'm too aggressive about short-circuiting when anything goes wrong with one of the questions.

This might be OK but I should double-check all my error handling to make sure giving up on the request is OK, or if I should try to set the rcode conservatively (NAME_ERROR if any of the questions had a name error) but keep going and try to return as many useful records as I can find.

shore up "lost" request logic

  1. Install unhandled exception handlers to make sure I'm getting all my logs
  2. Consider adding object lifetime hooks (maybe the new Cleaner API?), and set some state in Request objects so that they mark when an answer has gone out for them, and then in the hook, if the request hasn't been answered, mark that request as lost in prometheus (increment a new requests_lost metric)
  3. Go through and put extra guardrail logic in to see if we can get better coverage of exception handling: there's small bits of logic that I think might be able to throw exceptions that won't get caught, like when we're setting up callbacks and such.

icloud mail loading issues

Aug 03 16:13:46 claudius 0118ce86b176[40937]: 2023-08-03T16:13:46.540-0500 INFO InitialCheckingState - [Q] [192.168.1.169]: QNAME: 200608._domainkey.e.atlassian.com, QTYPE: TXT, QCLASS: IN | 5eacc677-3358-44d9-a8dc-521f51954161
Aug 03 16:13:46 claudius 0118ce86b176[40937]: 2023-08-03T16:13:46.596-0500 INFO Request - [R] [Optional[/192.168.1.169]]: SERVER_FAILURE | 5eacc677-3358-44d9-a8dc-521f51954161

Refactor authoritative records container

  • extract an interface
  • implement one backed live by the db

the main issue is that I precompute PTR and NS records. But I probably shouldn't.

  • move PTR and NS record generation to the rails frontend
  • add a convenience button that auto-gens PTR records for all existing A records.

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.