Dnmasq with public domain, split dns

Hi!
How to run dnsmasq with a public domain?
I tried some different solutions, but none of them is really satisfying.

Current config that works somewhat... :smile:

....
	list server '/public.com/ipofnameserver'
	list server '/public.com/ipofnameserver'
....
	option domain 'public.com'
	option local '/public.lan/'

setting option local to '/public.com/' breaks external name resolution of public.com
e.g. ping to public.com and all subdomains that are not handled by dnsmasq will fail.
Overwriting with list server '/public.com/ipofnameserver' doesn't seem to work.

They I use the cname option to remap external subdomains to local subdomains.
For example:

config cname
	option cname 'ftp.public.com'
	option target 'nas.public.com'

The domain options doesn't seem to be a good choice here because it overwrites the primary domain name of the system.
e.g. When doing a reverse lookup, 192.168.0.1 will return ftp.public.com instead of nas.public.com.

And it seems like that this all breaks dns to ipv6 mapping.
Or the odhcpd-update is bugged?

root@openwrt:/usr/sbin# ./odhcpd-update
BusyBox v1.31.1 () multi-call binary.

Usage: basename FILE [SUFFIX]

Strip directory path and .SUFFIX from FILE
root@openwrt:/usr/sbin# cat odhcpd-update
#!/bin/sh
# Make dnsmasq reread hostfile by sending SIGHUP signal

. $IPKG_INSTROOT/lib/functions/procd.sh

procd_send_signal dnsmasq

Shouldn't this be:

root@openwrt:/usr/sbin# cat odhcpd-update
#!/bin/sh
# Make dnsmasq reread hostfile by sending SIGHUP signal

. /lib/functions/procd.sh

procd_send_signal dnsmasq

?
//edit
nvm dnsmasq reloads fine.
//edit2
seems like ipv6 name resolution doesn't work because /tmp/hosts/odhcpd isn't added to the jail.
But I have to debug this a bit more...

What is the purpose of this configuration?
Are you going to serve the "public . com" from dnsmasq for the internet?
Generally Split (or DMZ or Stealth) DNS server can be accomplished with Bind, I am not sure dnsmasq was made for that, nor could I find anything in a quick search of its manual.

Have you created a PTR for that or you depend on what the dnsmasq will return?

1 Like

The purpose is:
Allowing access to services on the local/dmz network through the public internet.
And allowing usage of the public domain (+subdomains) on the local network.
But the (sub) domains mapped to the local IPs.
With this setup I can use the public domain everywhere with proper certificates.

I depend on what dnsmasq will return.
Of course, I could create a domain entry and then a cname on of that.
That actually would make more sense then depending on the dhcp name + cname option.
But I don't know how to do this for both IPv4+IPv6.

Something like:
//edit
that works

config domain
	option name 'nas'
	option ip 'IPv4 here'

config domain
	option name 'nas'
	option ip 'IPv6 here'
	
config cname
	option cname 'ftp.public.org'
	option target 'nas.public.org'

Do you have a pool of public IPs in your dmz? Or you are just port forwarding?

Does that mean to type the name www. public. com in the browser of a host in the lan and see the same as some host from the internet would see?

I don't think you need to go into all this trouble with the local/domain option in dnsmasq.
Just create more "domain" entries in dnsmasq as you have and instead of name 'nas' use name 'nas. public. com'
Otherwise you'll have to look at views in bind.

1 Like

No, but I want it to be future proof.

Yes, but the host from the LAN get a local IP returned.

Using an FQDN doesn't seem to work.
Also as I wrote in my first post using the domain option overwrites the real hostname of a hosts when doing an reverse lookup.
And using public.lan for example and then doing a remap through domain or cname will results in the hosts using the public ipv6 address instead of the ULA address.

//edit
off topic but here is patch that fixes:

  • servers file not added to jail
  • odhcpd lease file not added to jail
  • add negative domain name caching option
    -- addn host file(s) still needs to be fixed
--- /rom/etc/init.d/dnsmasq	2020-03-01 20:01:22.000000000 +0100
+++ /etc/init.d/dnsmasq	2020-03-04 19:26:35.000000000 +0100
@@ -898,6 +898,7 @@
 	append_parm "$cfg" "max_ttl" "--max-ttl"
 	append_parm "$cfg" "min_cache_ttl" "--min-cache-ttl"
 	append_parm "$cfg" "max_cache_ttl" "--max-cache-ttl"
+	append_parm "$cfg" "neg_ttl" "--neg-ttl"
 	append_parm "$cfg" "pxe_prompt" "--pxe-prompt"
 	config_list_foreach "$cfg" "pxe_service" append_pxe_service
 	config_get DOMAIN "$cfg" domain
@@ -1064,6 +1065,12 @@
 		done
 	}
 
+	config_get SERVERSFILE "$cfg" "serversfile"
+
+	if ! ODHCPDLEASEFILE="$(uci -q get dhcp.odhcpd.leasefile)"; then
+    ODHCPDLEASEFILE=""
+  fi
+
 	procd_open_instance $cfg
 	procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid
 	procd_set_param file $CONFIGFILE
@@ -1071,7 +1078,7 @@
 	procd_set_param respawn
 
 	procd_add_jail dnsmasq ubus log
-	procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE $RFC6761FILE $DHCPBOGUSHOSTNAMEFILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript /etc/hosts /etc/ethers /sbin/hotplug-call $EXTRA_MOUNT $DHCPSCRIPT
+	procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE $RFC6761FILE $DHCPBOGUSHOSTNAMEFILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript /etc/hosts /etc/ethers /sbin/hotplug-call $EXTRA_MOUNT $DHCPSCRIPT $SERVERSFILE $ODHCPDLEASEFILE
 	procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
 
 	procd_close_instance

Okay, I think, I got a working solution that doesn't leak internal dns requests to the outside.
The problem is, when using option local '/public.com/' in dnsmasq conf, dyndns scripts update will fail cause public.com can't be resolved.
At my dyndns provider, I have registered a public domain and set up a bunch of cnames because atm I only have one public IP.
So to make dyndns work, either setup a new cname like checkip.public.com that points to your domain (that is updated through dyndns) or choose an already existing cname or choose a different way to verify the IP in dyndns scripts.

DNSMASQ setup:

	option domain 'public.com'
	option local '/public.com/'
	list server '/checkip.public.com/IPofDynDNSNameServer' # Get from NS Record
	list server '/checkip.public.com/IPofDynDNSNameServer' # Get from NS Record

Change checkip.public.com to your corresponding cname that is linked to your dyndns updates.

When using option local '/public.com/' and you try to connect/ping from the lan side to public.com it will fail.

To fix that:
In dnsmasq conf:

config cname
  option cname 'public.com'
  option target 'openwrt.public.com' # Change openwrt to the hostname of your openwrt box

This will remap public.com to your router ip. If you want your public IP instead, choose either checkip.public.com or any other cname that is linked to your public IP.

Now all your internal host are mapped to *.public.com (with internal IPs from either DHCP or manually set up) but if you have hostnames that are only reachable on the public internet and should also be avaiable on the lan side:

config cname
	option cname 'ftp.public.com' # Public name
	option target 'nas.public.com' # Internal name

Or if you want to return your public IP or anything else that is listened at your dyndns DNS Server:
list server '/ftp.public.com/IPofDynDNSNameServer'

So with this setup is possible to invoke a "real" certficate from lets encrypt for example and use it anywhere on your network.

I think this is a good solution?

I also bought a public domain for my internet facing services, but internally I am using a different suffix.
All public records are defined in the DNS hosting.
For a few services that I need to use from inside I have a config domain entry in the config/dhcp that resolves to the private IP.
I don't know if it is worthy to go into all this trouble, but I don't know the size and the growth rate of your domain. Maybe if it is continuously growing and you don't want to manually add the hosts, it is worthy to automate it like you did.

Unfortunately, the solution I posted above doesn't work 100 %.
public.com only resolves when the cname reference is resolved first. The only solution I see here is to remove option local from the dnsmasq config.

As wrote in my first post, it overwrites the primary hostname/domain name for that host. When you do a reverse lookup e.g. nslookup iphere it returns the domain that got overwritten by the config domain option.
Also when option domain is not set to public.com, the hosts will try to use the public ipv6 for that host.(because public.com isnt't set as search domain via DHCP?)
I want to avoid that too. The hosts should use the ULA IP on the local network.

For the search part you can fix it with dhcp option 119. Also with option 15 you can assign the domain.

Maybe you could give a more detailed example using IPs and FQDNs? I am still confused of what is the problem in your scenario.

1 Like

I've been following the thread; and I'm still confused too:

  • I'm thinking the OP's trying to use OpenWrt as both a Public DNS server and as LAN DNS...that's not suggested
  • This is not how split-horizon DNS is commonly configured
  • I noticed the OP noted that a lookup doesn't work until the CNAME is looked up - that's how it's supposed to work
  • I still don't know if the OP's trying to make a Public Authoritative DNS Server for any domain

Sorry, if I made myself not clear enough...

I have a domain that hosted on public DNS server (let's call it public.com) and I want to use this public domain for both public access and local access.
The name server on the internet should provide public IPs addresses.
Currently, this is only 1 public IP.
The A and AAA record for this public domain (public.com) are updated through DynDNS.
I switched over from using a bunch of cname remaps to use a wildcard subdomain.
This all works fine.
DNSMASQ on the local network should use public.com as an internal domain.
All hosts on the local network should be mapped like this:
host1 -> host1.public.com -> local IPv4 / ULA IPv6
host2 -> host2.public.com -> local IPv4 / ULA IPv6
And so on...
All none local hostnames and unknown hostnames should not be forwarded upstream.
Only certain hostnames that are separately configured should be forwarded.
Notes:
Using the dnsmasq/uci domain option to remap domains is not an option.
Because this breaks ULA IPv6 and overwrites the "real" hostname of a host.

Current solution:

/etc/config/dhcp

  option local '/public.com/'
  option domain 'public.com'

Note:
public.com and all subdomains (hosted on the public DNS Server) can't be resolved, as expected.
This will break dyndns updates, when domain lookup method is specified.
To fix this, I created a new subdomain (or use wildcard subdomain), cname that points to your subdomain or domain that is updated through dyndns.
For example;
public.com is updated through dyndns.
checkip.public.com is cname subdomain pointing to public.com
Then add (/etc/config/dhcp)

 	list server '/checkip.public.com/IPofNameServerFoundinPublicDNS'
	list server '/checkip.public.com/IPofNameServerFoundinPublicDNS'

This allows dyndns scripts to verify the IP.
Other "problem" public.com will not resolve to anything.
I used this for public.com:
/etc/config/dhcp

config domain
  option name 'public.com'
  option ip 'IPv4'

config domain
  option name 'public.com'
  option ip 'ULA IPv6'

When I was running a http/s server, I would use instead:

config cname
	option cname 'public.com'
	option target 'www.public.com'

And www.public.com is either definied through config domain or dhcp.

The question is now, is there a better solution?
One problem with this solution is, if someone wants public.com to resolve to the public IP (that is updated through dyndns) and adds:

	list server '/public.com/IPofNS'
	list server '/public.com/IPofNS'

That doesn't work. For subdomains it does work fine, though.
However, for my purpose it works fine now.
I can issue, an cert from lets crypt via acme.
And can use this cert anywhere on my network (luci,ftp and so on), local and public wise.

//edit

Using the dnsmasq/uci domain option to remap domains is not an option.
Because this breaks ULA IPv6 and overwrites the "real" hostname of a host.

Seems like I'm wrong about the ULA IPv6 part.
It is a mystery to me how Windows decides when to use ULA IPv6 or the public IPv6.

Simple solution:

  • simply make all config domain entries that are only valid locally - directly on the OpenWrt using the LAN IP - this is the normal recommendation; or
  • configure the firewall to redirect these services via a Port Forward - from the Public IP connection looped to the WAN to the LAN server

Also:

  • configure DDNS to use the Interface in question as its IP hint to update, not domain lookups...

A lot of what you have is just wrong, and doesn't work; but you state that you expect it to work...that leads me to believe there's a fundamental misunderstanding of DNS.

You cannot use a Private ULA IP to connect on the Pubic Internet to the server.

Already tried that. If DHCP is also uses as fallback with static leases, dnsmasq appends those IP addresses to the domain entry.

That sounds like a bad idea.

How does dyndns know when I update is needed?
It gets the (public) IP from either the network/interface itself or uses different source (like a website)
then does a domain lookup (domain that is specified in dyndns settings) and compares both values.
So if the domain (in this case public.com) can't be resolved or resolves to a local IP, the update will fail.

WTF?

They should be the same IP. You have a server, a server needs a static IP, hence why you workaround by the common rig of DDNS.

Yes, it uses CPU resources for iptables, the alternative is the config domain (many threads on this), use the other suggestion - they should be the same and correct IP. Otherwise, you're doing something wrong.

Time.

:man_facepalming:

Yes, so you should stop configuring this circular dependency. You do realize you're making these configs, correct?

The IP should only be updated from its true source. I assume this is your real WAN?

If so, the proper DDNS setting is ans always should be - the WAN.

They have a static IP.
DHCP static leases configured as fallback.
When I configure a static domain entry in dnsmasq and a host gets a DHCP lease, dnsmasq (or better the lease from odhcpd) gets added to this entry.
The result is, when doing a nslookup, some IPs get listened twice.
Not a big a deal....

Yes and the dyndns scripts in openwrt check if the IP has actually changed.
Through domain lookup and comparison with the interface IP.
If they mismatch the script tries to update.

Yes and the config does work.
The IP is updated from the true source. The "true source" is compared with the configured lookup domain in dyndns config as I have explained above.

To be clear, are these Public IP addresses, if not, you need to follow a course more tuned to my advice.

???

You misconfigured that anyway!

And you said it updates by checking the DNS record...if that is incorrect, please clarify.

I'm honestly having a hard time trying to following this convoluted mess; but I digress - I cannot find the exact quote.

My point was, DDNS should be set to update from the WAN's PHY interface name. If that is so, please make that clear as well.

(And BTW, RFC dictates example.com for examples - there's also example IPs...cause this is getting deep!)

The result is, when doing a nslookup, some IPs get listened twice.
Maybe the sentence makes more sense now.

:smile:

Not it is not.
Please check the ddns package.
The user can choose how to determine the WAN IP, either directly from the interface or from a different source.
Then the ddns scripts expects that the user entered a lookup domain/host.
The script checks the WAN interface IP and compares it to the IP from the lookup domain/host.
(option lookup_host)
When they don't match, the domain (option domain) is updated with the new IP.

example.com is not used in a real case scenario.

Correct, and it should be WAN, correct???

Your ISP does actually issue you this true Public IP to that interface, right!?!? So that's what you have it set to, correct?

And then you configured a loop in your OpenWrt DNS...CORRECT?

So that does have to be "a WRONG config"....correct?

Do you mean "resolved twice"? (I was gonna correct you, but I wanted you to respond...and you repeated the word "listened".)

You really didn't visit that site, did you?


You do understand what "horizon" in Split Horizon DNS means, correct?

:thinking:

You also never clarified if this network has Public IPs...otherwise your logic still doesn't make sense. I wanted to be sure if they were Public or Private.

Also, to be clear, you configured the DNS servers of the DDNS provider...correct?

...and didn't expect an instantaneous update from new IP to resolution...correct?

Yes.

Nope.

For example:

nslookup nas.example.com
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:      nas.example.com
Address 1: 10.0.x.x
Address 2: fd13:3:7:x::x #  same as 3
Address 3: fd13:3:7:x::x  # same as 2

No :smile:

It is not a true 1:1 split.
Because the public side has not the same DNS entries as the local side.

The entire thread is about this.
Yes, it has.
But only one public IP.
And all hostnames like ftp, www and others should be mapped to the public IP.
When a host on the internet resolves one of those (sub) domains.
Host on the internal LAN should resolve (sub)domains to local IP.
The above setup does that.

Yes, the DDNS part is comepletely fine.

What do you mean?
IP is only updated when the WAN IP has changed.
The TTL of the dyndns DNS entry is set to 2min.
So the new IP should be quickly propaganted.