janeczku/go-dnsmasq

feature request, wildcard host resolution from hostfile

titpetric opened this issue · 5 comments

I'd like to request a feature, a bit of an extension of the hosts file. I'd like to add support for a wildcard domain. I would suggest implementing it as:

IP1  *.server.lan server.lan
IP2 mail.server.lan

I would want it to work similar to nginx server_name directive. Meaning:

resolve server.lan to IP1 (exact match, as now)
resolve mail.server.lan to IP2 (exact match, as now)
resolve www.server.lan to IP1 (wildcard match, new)

My main use is running a VM guest locally on the laptop, using it for a DNS to avoid modifying hosts file on the host. Several projects have a catch-all domain entry point, where it wouldn't be feasible for me to create many hosts file entries, and bind* or other dns servers take too much of configuration / maintenance.

If you're willing to accept a pull request from a newbie, I can also work on implementing the above in Go. I guess I could swing it, even if Go is not my default language :)

Best,
Tit

I think we can do that.
Also let's keep it simple and cheap so just one level of wildcard lookup.
Given a hosts file of:

192.168.0.1 www.server.lan 
192.168.0.2 *.server.lan 

Query www.server.lan resolves to 192.168.0.1
Query www2.server.lan resolves to 192.168.0.2
Query www.subdomain.server.lan will not be resolved

Should be easy to implement. hostname struct gets an additional field. When we do wildcard lookup check for a hostname with matching hostname.domain and hostname.wildcard set to true.

type hostname struct {
    domain  string
    ip           net.IP
    ipv6       bool
    wildcard bool
}

PR is welcome! 😄

I've made some modifications, and even extended tests with new wildcard functionality. I figured out how to build dnsmasq with scripts/build, but I'm quite unfamiliar with golang dev/build/test steps. How can I run the tests inside hostsfile_test.go? I don't want to leave the hard parts to you :)

Just leaving some information here for posterity before I submit a PR:

I figured out that the test are not updated, so I updated them. Most notable change since the tests were written, is that parseLine rejects link-local definitions (ipv4 and ipv6) with IsGlobalUnicast + ParseIP("fe00::"). I didn't try to change this behavior, but I did update the tests to use some valid IPv6 and IPv4 IPs. Tests are updated with wildcard matches, and I added an Equal method to hostname to check equality - tests wanted it, but was missing.

I'm running the test with the following command:

# docker run --rm=true -it -v `pwd`:/go golang go test -v
=== RUN   TestEquality
--- PASS: TestEquality (0.00s)
=== RUN   TestParseLine
--- PASS: TestParseLine (0.00s)
=== RUN   TestHostname
--- PASS: TestHostname (0.00s)
PASS
ok      _/go    0.002s

I moved some code around, just to make it accessible for testing. Most notably, I put FindHost and FindHosts method in hostlist struct, and did some other restructuring as well.

I tested that running scripts/build works for me, but I didn't test if the output / dnsmasq works as expected after the change. I hope the unit test is enough and that I didn't break any behavior here.

Verified the modifications work as expected:

> server 127.0.0.1
Default server: 127.0.0.1
Address: 127.0.0.1#53
> test.my.lan
Server:         127.0.0.1
Address:        127.0.0.1#53

Non-authoritative answer:
Name:   test.my.lan
Address: 49.1.1.1
> anything.my.lan
Server:         127.0.0.1
Address:        127.0.0.1#53

Non-authoritative answer:
Name:   anything.my.lan
Address: 49.1.1.1
> my.anything.my.lan
Server:         127.0.0.1
Address:        127.0.0.1#53

** server can't find my.anything.my.lan: NXDOMAIN

With hosts file:

49.1.1.1 *.my.lan

Thanks for the opportunity to write some golang :) I hope I didn't step on any toes while restructuring FindHosts a bit. Let me know if some corrections are needed on your side.