Mikael Bendiksen Mikael's BrainDump

A place to put my ideas

Froste

CTF Brain Meets UniFi Gateway: Solving the setup.ui.com Mystery

The problem

UniFi offers a robust and reliable range of networking equipment. In my homelab, I’ve been running their gateway, controller, switches, and access points for an extended period, and they’ve consistently delivered solid performance and ease of management.

Image Description

However, after replacing my old pfSense box with the UniFi Gateway Max (UXG-MAX), I encountered some unexpected issues. The device initially struggled to adapt to my local setup, and oddly enough, those issues were only resolved after first linking it to a UniFi Cloud Controller, and then migrating it to my Cloud Key Gen2 Plus (UCK-G2-PLUS). Despite the migration, one quirk remained: the so-called “convenience” URL setup.ui.com, which is used during the initial setup of the gateway never deactivated itself. As a result, reverse DNS lookups for the gateway’s IP consistently returned that URL, which was not the intended behavior.

Image Description

It got to a point where I decided that it was time to fix it, but how?

Understanding why

According to my support inquiry with UniFi Support, the setup.ui.com URL is assigned when a device is in its initial adoption state or has been factory reset. This web interface is designed to simplify the adoption process, particularly for users without a dedicated controller.

Once a device has been successfully adopted, it is expected to update its reverse DNS (PTR) record to reflect the device’s assigned name rather than the default setup.ui.com.

To make it even worse, the setup.ui.com URL has a self-signed certificates and gives the error: NET::ERR_CERT_AUTHORITY_INVALID.

Image Description

The error NET::ERR_CERT_AUTHORITY_INVALID in Google Chrome means that the browser does not trust the certificate authority (CA) that issued the website’s SSL/TLS certificate. This typically happens with self-signed certificates or certificates issued by a private/internal CA.

You can however access the site if you use the IP of the gateway, but it only tells us what we already know and does not fix the issue.

Image Description

In my case, due to adoption issues that occurred over a year ago, this process didn’t complete properly. As a result, every time a change was made via the UniFi Network Console, a new configuration was pushed to the gateway and unfortunately, it continued to reintroduce the setup.ui.com entry in the configuration.

 {
    "hostName": "setup.ui.com",
     "registerNonQualified": false,
     "address": {
	   "address": "192.168.0.1",
	   "version": "v4"
    }
},

Device deepdive to find potential fix

Since the device runs a variety of open-source software packages on a Linux-based system, it was time to dig a bit deeper and see if there was a way to work around the issue.

The first step was to gain a better understanding of the software pipeline and how the various components are interconnected.

Device Firmware versions

UCK-G2-PLUS

  • Network 9.1.120
  • UniFi OS 4.2.12

UXG-MAX

  • 4.1.13 FW

UDAPI

UDAPI is a framework used for processing Universal Dependencies data, and in the UniFi system, it aggregates all controller-provided configuration into a JSON file located at /data/udapi-config/udapi-net-cfg.json.

This file contains the complete configuration that the device relies on to initialize and manage its software components. Notably, the configuration snippet responsible for the setup.ui.com entry.

 {
    "hostName": "setup.ui.com",
     "registerNonQualified": false,
     "address": {
	   "address": "192.168.0.1",
	   "version": "v4"
    }
},

UDAPI is responsible for launching the necessary services, passing the appropriate runtime arguments, and generating dynamic configuration files within the /run directory for each component. All based on the contents of the JSON configuration.

Image Description As you can see in this image the /usr/bin/ubios-udapi-server process has a lot of sub processes to other applications due to this.

DNSMASQ

One of the key open-source components involved is DNSMASQ, which is responsible for handling reverse DNS (PTR) lookups. The very behavior we’re trying to correct.

dnsmasq is a lightweight, easy-to-configure DNS forwarder and DHCP server used widely in embedded systems, routers (e.g., OpenWRT), and local networks.

As we can see in the process tree its running with the following parameters:

/usr/sbin/dnsmasq --conf-dir=/run/dnsmasq.conf.d/ --pid-file=/run/dnsmasq.pid --resolv-file=/etc/resolv.dnsmasq

As we’ve already established, the /run/dnsmasq.conf.d/ directory is dynamically generated each time a new configuration is deployed via UDAPI. This means any manual changes made there are overwritten on the next update, and since DNSMASQ relies on those files, modifying them directly isn’t a viable long-term solution especially without a reliable way to trigger a reload.

That leaves us with the /etc/resolv.dnsmasq file as a potential workaround, since it directly relates to the DNS resolution process we’re aiming to correct.

# Generated automatically by ubios-udapi-server
search bb.online.no 

# dynamic nameservers
# eth3
# disabled 192.168.3.1
# tunovpnc1
# disabled 10.0.0.243
# static nameservers
# eth4
nameserver 1.1.1.1
nameserver 8.8.8.8

Sadly its only contains the forwarding DNS servers and that is also configurable in the controller.

String searching in files

By this point, it was late at night, and my CTF instincts kicked in. I decided to search the system for any files containing setup.ui.com to uncover more clues about the software components involved and gain deeper insight into the issue.

root@UXGMax:~# grep -rnw '/run' -e 'setup.ui.com'
/run/dns.conf.d/dnsmasq-tunovpnc1.conf:18:host-record=setup.ui.com,192.168.0.1
/run/dns.conf.d/dnsmasq-eth3.conf:18:host-record=setup.ui.com,192.168.0.1
/run/dns.conf.d/dnsmasq-eth4.conf:18:host-record=setup.ui.com,192.168.0.1
/run/dnsmasq.conf.d/dns.conf:17:host-record=setup.ui.com,192.168.0.1

We know the files in /run was generated by UDAPIso they could not be altered and would not persist.

After some time i found the default configuration files for UDAPI used by UniFi in the following location:

/usr/share/ubios-udapi-server/uxg-a690.default 
/usr/share/ubios-udapi-server/uxg-a690.fallback

One is the first default deployment and the other one is a fallback if a configuration deploy broke.

root@UXGMax:~# grep -A 7 -B 2 "setup.ui.com" /usr/share/ubios-udapi-server/uxg-a690.default
"hostRecords": [
	{
		"hostName": "setup.ui.com",
		"address": {
			"address": "192.168.1.1",
			"version": "v4"
		},
		"registerNonQualified": false,
		"ttl": 60
	},

Sadly after editing this files, restarting the device and clearing my DNS cache it did not help and the rDNS (PTR) still responded with setup.ui.com.

The fix is always right in front of you

While investigating where dnsmasq stores its reverse DNS records, I realized an important detail: by default, DNSMASQ does not store reverse DNS entries persistently. Instead, it dynamically serves PTR lookups based on three distinct sources.

DHCP Leases File

When DNSMASQ is used as a DHCP server, it can dynamically provide reverse DNS based on the current leases.

/var/lib/misc/dnsmasq.leases

This file contains current leases, and DNSMASQ uses it to provide forward and reverse DNS entries for clients.

Static DHCP Configuration

In your dnsmasq.conf or included config files (e.g., /etc/dnsmasq.d/*.conf), you might have entries like:

dhcp-host=aa:bb:cc:dd:ee:ff,set:device1,192.168.1.50,mydevice

This creates a static lease and allows reverse resolution of 192.168.1.50 to mydevice.

/etc/hosts

If you add entries like:

192.168.1.10 myhost.lan

Then DNSMASQ will serve a DNS and most importantly in our case, reverse DNS (PTR) entry for 192.168.1.10 to myhost.lan.

Solution

One thing I’ve learned over the years especially through countless CTF challenges is that processes like these often resolve certain values before any configuration files or runtime arguments are even considered.

That got me thinking: could it really be as simple as adding a line like 192.168.0.1 UGXMax.bendiksens.net to /etc/hosts and effectively hijacking the .arpa resolution before the system processes the dynamic configuration?

Let’s try it out.

root@UXGMax:~# cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       UXGMax  # local hostname added automatically by ubios-udapi-server
192.168.0.1 UXGMax.bendiksens.net
# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

After rebooting the device, I was pleasantly surprised to see that the entry I added to /etc/hosts persisted. Encouraged by this, I began testing the behavior on my desktop by first flushing the DNS cache, then running a series of tests using dig, tracepath, and reviewing the route table to confirm.

duux@DorrisV2:~$ resolvectl flush-caches

duux@DorrisV2:~$ dig -x 192.168.0.1

; <<>> DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu <<>> -x 192.168.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3332
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;1.0.168.192.in-addr.arpa.      IN      PTR

;; ANSWER SECTION:
1.0.168.192.in-addr.arpa. 1     IN      PTR     UXGMax.bendiksens.net.

;; Query time: 2 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Thu Jun 05 01:47:29 CEST 2025
;; MSG SIZE  rcvd: 88

duux@DorrisV2:~$ tracepath vg.no
 1?: [LOCALHOST]                      pmtu 1500
 1:  UXGMax.bendiksens.net                                 0.564ms 
 1:  UXGMax.bendiksens.net                                 0.572ms 
 2:  ti0182a400-gw.ti.telenor.net                          1.832ms 
 3:  no reply
 4:  ti0300b315-ae1-0.ti.telenor.net                       1.894ms 
^C

duux@DorrisV2:~$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         UXGMax.bendikse 0.0.0.0         UG    100    0        0 enp5s0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.0.0     0.0.0.0         255.255.254.0   U     100    0        0 enp5s0

HOLY SHIT! IT WORKED!

And it even seems to persist over changes in controller and reboots.

However, the config file that UDAPI uses, still is been populated with the entry on changes.

 {
    "hostName": "setup.ui.com",
     "registerNonQualified": false,
     "address": {
	   "address": "192.168.0.1",
	   "version": "v4"
    }
},

Lucky the workaround going in before it is applied.

Follow-up with Support

As of writing this my support case is still ongoing.

I’m going to loop in one of our product experts to ensure this can be addressed as quickly and satisfactorily as possible. They will reach out once they’ve had the opportunity to sufficiently review.

I’ve shared my workaround with them and asked for confirmation on whether it’s an acceptable and supported solution.

Please escalate it as planned. I’d like to ensure that the proposed workaround is viable as a long-term solution.

Will update once I get a response from them.

UPDATE 2025-06-06

I would like to mention that the problem you are facing is unusual and unexpected.

I found similar posts on the web of people having the same issue. It’s strange that they don’t know about this issue as it seems to be some what small, but common issue ranging from 9 years back to so early as few months.

Reddit post Unifi Forum

New logs have been sent to support.

UPDATE 2025-07-04

It’s been a month now and small messages has passed back and forth between me and Support.

Mostly the messages have been:

We’ve consulted with the development team regarding the workaround. While we cannot definitively rule out the possibility of unintended side effects, the team believes there is an opportunity to improve the situation within the Network Application. Specifically, we can prioritize custom DNS settings over default records—such as setup.ui.com—to ensure that custom DNS entries are resolved before the defaults.

And periodically updates like this:

Just wanted to keep you informed that we are currently confirming with our development team regarding this issue. We will be sure to update you as soon as we receive any further information from them. Thank you for your patience and understanding.

Today I got the following message from support:

We have received confirmation from the development team that the workaround you applied is suitable for now. It will be improved in a future version of the Network Application; however, we currently do not have an ETA of the release. You can monitor the latest releases at this link for updates.

From the looks of it they have identified that this is an issue they plan to address in the Network Application and my fix is suitable for now.

Can also report that devices have been updated with newer versions and the fix is still in place and persists with Network 9.2.87

UPDATE 2025-11-25

Well, that did not last long. Right after last update Ubiquity updated the gateway ( Network 10.0.162 & Gateway 4.3.1) with a new version that uses no-hosts configuration in dnsmasq.

The no-hosts option in dnsmasq is a configuration directive used to instruct the service to not read the standard system /etc/hosts file. This is useful in specific scenarios where you want dnsmasq to manage DNS records exclusively through its own configuration files (like dnsmasq.conf) or rely solely on upstream DNS servers, ensuring system-wide host entries do not interfere with its operation.

This means that the workaround will not work anymore and setup.ui.com is forced again!

Had a new talk with support regarding this and they just gave me this response after explaining this to them 3 times before they understood the problem…

Hello Mikael,
  Thank you for your detailed follow-up and for sharing your continued feedback on this behavior. I truly wish there were a quick fix or workaround that could be applied, but as you mentioned, the current configuration prevents any manual changes from persisting. Our engineering team has acknowledged this improvement, and the enhancement to allow custom hostnames to take precedence over the default setup.ui.com entry is planned for a future update.

Looks like we just need to wait for the “future” update….

UPDATE 2026-02-13

UniFi Network Application 10.1.84

Interesting patch notes in Network 10.1.84:

  • Improved the user experience for configuring static IP addresses for devices.
  • Added validation for Loopback IP addresses in the Network Settings.
  • Added various new endpoints to the Network API:
    • Device Removal.
    • UniFi Device Adoption.
    • Wireless Device Adoption.
    • DNS policy creation and management.
    • Firewall policy creation and management.
    • Listing VPN servers and Site-to-Site tunnels.

None of them seem to have any connection to the setup.ui.com

Config changes in gateway 5.0.12

Installed the new gateway update Gateway 5.0.12 as well. Some of the internal configuration paths have changed.

root@UXGMax:~# ps aux | grep dnsmasq  
nobody     65744  0.1  0.2   7928  4192 ?        S<   14:00   0:01 /usr/sbin/dnsmasq --pid-file=/run/dnsmasq-main.pid --resolv-file=/run/resolv.conf.d/main --conf-file=/run/dnsmasq.dns.conf.d/main.conf --conf-dir=/run/dnsmasq.dhcp.conf.  
d/  
root       65746  0.0  0.1   7800  2916 ?        S<   14:00   0:00 /usr/sbin/dnsmasq --pid-file=/run/dnsmasq-main.pid --resolv-file=/run/resolv.conf.d/main --conf-file=/run/dnsmasq.dns.conf.d/main.conf --conf-dir=/run/dnsmasq.dhcp.conf.  
d/  
nobody     65749  0.0  0.2   7800  4116 ?        S<   14:00   0:00 /usr/sbin/dnsmasq --pid-file=/run/dnsmasq-wgclt3.pid --resolv-file=/run/resolv.conf.d/wgclt3 --conf-file=/run/dnsmasq.dns.conf.d/wgclt3.conf  
nobody     65756  0.0  0.2   7800  4096 ?        S<   14:00   0:00 /usr/sbin/dnsmasq --pid-file=/run/dnsmasq-eth4.pid --resolv-file=/run/resolv.conf.d/eth4 --conf-file=/run/dnsmasq.dns.conf.d/eth4.conf  
nobody     65758  0.0  0.1   7800  3948 ?        S<   14:00   0:00 /usr/sbin/dnsmasq --pid-file=/run/dnsmasq-eth3.pid --resolv-file=/run/resolv.conf.d/eth3 --conf-file=/run/dnsmasq.dns.conf.d/eth3.conf

and looking in the /data/udapi-config/udapi-net-cfg.json file the entry is still in config, however it does not have any entry assorted to it anymore:

  {  
    "hostName": "setup.ui.com",  
    "registerNonQualified": false,  
    "address": null  
   },

But looking in the dnsmasq config at /run/dnsmasq.dns.conf.d/main.conf:

interface-name=setup.ui.com,br0

So they have moved it away from the DNS entries and put it as a interface-name.

interface-name=<name>,<interface>: This option is for returning a specific DNS record (A and PTR) that associates a given hostname with the primary IP address of a specified interface, essentially acting like a dynamic /etc/hosts entry based on the interface’s current IP.

duux@DorrisV2:~$ traceroute --resolve-hostnames -m 1 vg.no  
traceroute to vg.no (108.157.229.114), 1 hops max  
 1   192.168.0.1 (setup.ui.com)  0.392ms  0.472ms  0.315ms

This might be how they aim to fix this. All they need to do now is have a ability in the UI to set this value in the future right?

Ill keep digging to see if its a way to override this with the new software changes.

ns.unifi.ui.local

Also some weird behavior happen to some of my DNS records set on the device. Some of them broke after the update using an SOA record of ns.unifi.ui.local. This results in a error as the ns.unifi.ui.local does not resolve to anything and no trace of it so far in the configs. I needed to remove the A record, wait for the timeout and then re-add it to fix it.

→ Q: ui.bendiksens.net IN A  
← S: NXDOMAIN  
← A: ui.bendiksens.net IN SOA ns.unifi.ui.local 0 7200 900 1209600 86400 0  
duux@DorrisV2:~$ dig ns.unifi.ui.local @192.168.0.1  
  
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> ns.unifi.ui.local @192.168.0.1  
;; global options: +cmd  
;; Got answer:  
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 44812  
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1  
  
;; OPT PSEUDOSECTION:  
; EDNS: version: 0, flags:; udp: 1232  
; COOKIE: 4d7d2435764d9828 (echoed)  
;; QUESTION SECTION:  
;ns.unifi.ui.local.             IN      A  
  
;; AUTHORITY SECTION:  
.                       1800    IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2026021300 1800 900 604800 86400  
  
;; Query time: 1 msec  
;; SERVER: 192.168.0.1#53(192.168.0.1) (UDP)  
;; WHEN: Fri Feb 13 14:57:05 CET 2026  
;; MSG SIZE  rcvd: 133