TechnitiumSoftware / DnsServer

Technitium DNS Server
https://technitium.com/dns/
GNU General Public License v3.0
3.83k stars 399 forks source link

Feature Request: Add a Docker Environment Variable for the Web Server Listening Address #877

Closed anonhostpi closed 3 months ago

anonhostpi commented 3 months ago

When running the DNS server in host mode (to support DHCP deployments), the Web Server port is also exposed and not protected by Docker's NAT.

This can be a problem when trying to protect the web console with a docker-based reverse/oauth-proxy.

To prevent unauthorized/unproxied access, you can set the listening address. As far as I am aware, the only place to configure this is on the web server, once it is already running:

image

Ideally in a Docker environment, this should be configurable from the docker compose file prior to starting the web server.

EDIT: Potential solution: https://github.com/TechnitiumSoftware/DnsServer/issues/877#issuecomment-1982246204

anonhostpi commented 3 months ago

Doing a code search for how this text field is handled...

Element ID: txtWebServiceLocalAddresses

That element gets sanitized for saving here:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/www/js/main.js#L1436-L1442

relevant HTTP request:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/www/js/main.js#L1733-L1752

and it is retrieved here:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/www/js/main.js#L958-L962

relevant HTTP request:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/www/js/main.js#L924-L937

anonhostpi commented 3 months ago

Settings API source code:

https://github.com/TechnitiumSoftware/DnsServer/blob/master/DnsServerCore/WebServiceSettingsApi.cs

anonhostpi commented 3 months ago

Relevant lines for setting the web addresss:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/WebServiceSettingsApi.cs#L570

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/WebServiceSettingsApi.cs#L703-L730

Note this line from the above blob:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/WebServiceSettingsApi.cs#L722

The restart of the server (and the application of the new listening address), starts here:

https://github.com/TechnitiumSoftware/DnsServer/blob/master/DnsServerCore/WebServiceSettingsApi.cs#L1344

anonhostpi commented 3 months ago

It is appears that while running, the webserver uses _dnsWebService._webServiceLocalAddresses for storing the listening address

The class for this is defined here:

https://github.com/TechnitiumSoftware/DnsServer/blob/master/DnsServerCore/DnsWebService.cs

Here is the property:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L92

anonhostpi commented 3 months ago

This appears to be where the config is read from:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L1144

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L1151-L1166

Which is wrapped by this method:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L1108-L1142

Which is called by this method:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L858

Which loads the config file with this snippet:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L860-L875

anonhostpi commented 3 months ago

Config file (for the DnsWebService class) appears to be defined here on Linux:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerApp/Program.cs#L54

Which is pulled from the arguments passed to the executable:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerApp/Program.cs#L32-L33

Which for docker, is defined in the service file:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerApp/systemd.service#L6

anonhostpi commented 3 months ago

Next thing I need to do is to determine if I can even interact with that binary file (dns.config). When I try to cat it on ubuntu, I got a bunch of garbage in the output, so it does not appear to be plain text

anonhostpi commented 3 months ago

Looks like it should be easy to set it with the LoadConfigFile() method:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/DnsWebService.cs#L896-L910

You would just have to transpile the sanitization scripts and place them in the above blob

frontend:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/www/js/main.js#L1436-L1442

backend:

https://github.com/TechnitiumSoftware/DnsServer/blob/05ec6a5da4d7d05102c473974f6b0559b384de67/DnsServerCore/WebServiceSettingsApi.cs#L703-L730

anonhostpi commented 3 months ago

It looks like it might not even need to be that complicated, since cleanTextList just replaces newlines and removes additional commas

// Replace newlines with commas
string webServiceLocalAddresses = input.Replace("\n", ",")

// Replace duplicate commas with single commas
webServiceLocalAddresses = Regex.Replace(webServiceLocalAddresses, ",{2,}", ",");

// Trim the string of starting/trailing whitespace and commas
webServiceLocalAddresses = Regex.Replace(webServiceLocalAddresses, "(?:^[, ]+)|(?:[, ]+$)", ",");

// insert above snippet from DnsServerCore/WebServiceSettingsApi.cs (lines L703-L730)
// ...

I currently lack an environment to build and test on right now, but if someone thinks they can get a fork/PR spun up faster than me, please go for it. If not, I might have my lab back up and running by end of this week or next week.

ShreyasZare commented 3 months ago

Thanks for the request. Will get the environment variable added in the upcoming update.

anonhostpi commented 3 months ago

How is your release schedule? I'd like to know when I should check back.

ShreyasZare commented 3 months ago

How is your release schedule? I'd like to know when I should check back.

The next update is planned for upcoming weekend but it may get a bit delayed too. I will post here when its available so that you are notified.

ShreyasZare commented 3 months ago

Technitium DNS Server v12.1 is now available that adds the environment variable. Do update and let me know your feedback.

anonhostpi commented 3 months ago

Will do. Have inspections this weekend, so this will likely get implemented later this week

anonhostpi commented 3 months ago

New environment variable (DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES) will need to be added to the docker compose file.

Testing out the change now. Give me a bit

anonhostpi commented 3 months ago

Works for singular listening address.

DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES="172.18.0.1" # Single Docker bridge address

Rebuilding it for 2 addresses

DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES="172.18.0.1, 172.17.0.1" # Multiple Docker bridge addresses, comma-delimited

I'm not entirely sure if the environment variables can handle line returns, but I don't see why anyone would use line returns over the comma-delimiter for this. So I won't test that.

anonhostpi commented 3 months ago

It did not like the comma-delimited address

EDIT: also tried newlines with compose.yaml:

- DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES=|
          172.18.0.1
          127.0.0.1 # also changed this just in case it didn't like the docker bridge adapter

Did not work, but newlines seem like a strange way to do this from yaml, so I would worry about the prior, but not the latter.

anonhostpi commented 3 months ago

Here are the logs:

dns-dhcp-test  | System.FormatException: An invalid IP address was specified.
dns-dhcp-test  |  ---> System.Net.Sockets.SocketException (22): Invalid argument
dns-dhcp-test  |    --- End of inner exception stack trace ---
dns-dhcp-test  |    at System.Net.IPAddressParser.Parse(ReadOnlySpan`1 ipSpan, Boolean tryParse)
dns-dhcp-test  |    at TechnitiumLibrary.StringExtensions.Split[T](String value, Func`2 parse, Char[] separator) in Z:\Technitium\Projects\TechnitiumLibrary\TechnitiumLibrary\StringExtensions.cs:line 34
dns-dhcp-test  |    at DnsServerCore.DnsWebService.LoadConfigFile() in Z:\Technitium\Projects\DnsServer\DnsServerCore\DnsWebService.cs:line 898
dns-dhcp-test  |    at DnsServerCore.DnsWebService.StartAsync() in Z:\Technitium\Projects\DnsServer\DnsServerCore\DnsWebService.cs:line 2540
dns-dhcp-test  |    at TechnitiumLibrary.TaskExtensions.Sync(Task task) in Z:\Technitium\Projects\TechnitiumLibrary\TechnitiumLibrary\TaskExtensions.cs:line 56
dns-dhcp-test  |    at DnsServerCore.DnsWebService.Start() in Z:\Technitium\Projects\DnsServer\DnsServerCore\DnsWebService.cs:line 2668
dns-dhcp-test  |    at DnsServerApp.Program.Main(String[] args) in Z:\Technitium\Projects\DnsServer\DnsServerApp\Program.cs:line 55
dns-dhcp-test  | 
dns-dhcp-test  | Technitium DNS Server is stopping...
dns-dhcp-test  | Technitium DNS Server was stopped successfully.
dns-dhcp-test exited with code 0
anonhostpi commented 3 months ago

Got it. The compose file did not like the quotes, so in YAML you can use:

- DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES=172.18.0.1,127.0.0.1

image

Will be submitting a PR for the docker compose file

ShreyasZare commented 3 months ago

Thanks for the feedback and for the PR. Had missed updating the docker compose file to add it.