IPFire 2.29 - Core Update 203 released

I have looked through dhcp.cgi and also through unbound-dhcp-leases-bridge and I have not been able to find any code that extracts the text from the Remark section up to the first space in either of those packages.

If the text is not being extracted then it canโ€™t be assigned to a hostname.

Which package do you believe that this extraction of the first whole word is carried out?

In CU 202

// config/unbound/unbound-dhcp-leases-bridge
262: 	def update_dhcp_leases(self):
263: 		# Drop all known leases
264: 		self.leases.clear()
265:
266: 		# Add all dynamic leases
267: 		for lease in DHCPLeases(self.leases_file):
268: 			self._add_lease(lease)
269:
270: 		# Add all static leases
271: 		for lease in FixLeases(self.fix_leases_file):
272: 			self._add_lease(lease)
273:

And

// config/unbound/unbound-dhcp-leases-bridge
554: class FixLeases(object):
555: 	def __init__(self, path):
556: 		self.path = path
557:
558: 		self._leases = self._parse()
559:
560: 	def __iter__(self):
561: 		return iter(self._leases)
562:
563: 	def _parse(self):
564: 		log.info("Reading fix leases from %s" % self.path)
565:
566: 		now = datetime.datetime.utcnow()
567:
568: 		leases = []
569:
570: 		with open(self.path) as f:
571: 			for line in f.readlines():
572: 				line = line.rstrip()
573:
574: 				try:
575: 					hwaddr, ipaddr, enabled, a, b, c, hostname = line.split(",")
576: 				except ValueError:
577: 					log.warning("Could not parse line: %s" % line)
578: 					continue
579:
580: 				# Skip any disabled leases
581: 				if not enabled == "on":
582: 					continue
583:
584: 				l = Lease(ipaddr, {
585: 					"binding"         : "state active",
586: 					"client-hostname" : hostname,
587: 					"starts"          : now.strftime("%w %Y/%m/%d %H:%M:%S"),
588: 					"ends"            : "never",
589: 				}, fixed=True)
590: 				leases.append(l)
591:
592: 		return leases
593:

client-hostname is the field FIX_REMARK writed in /var/ipfire/dhcp/fixleases by dhcp.cgi

// html/cgi-bin/dhcp.cgi
457:     unless ($errormessage) {
458: 	$dhcpsettings{'FIX_REMARK'} = &Header::cleanhtml($dhcpsettings{'FIX_REMARK'});
459: 	$dhcpsettings{'FIX_NEXTADDR'} = &Header::cleanhtml($dhcpsettings{'FIX_NEXTADDR'});
460: 	$dhcpsettings{'FIX_FILENAME'} = &Header::cleanhtml($dhcpsettings{'FIX_FILENAME'});
461: 	$dhcpsettings{'FIX_ROOTPATH'} = &Header::cleanhtml($dhcpsettings{'FIX_ROOTPATH'});
462: 	if ($dhcpsettings{'KEY2'} eq '') { #add or edit ?
463: 	    unshift (@current2, "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n");
464: 	    open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
465: 	    print FILE @current2;
466: 	    close(FILE);
467: 	    &General::log($Lang::tr{'fixed ip lease added'});
468:
469: 	    # Enter edit mode
470: 	    $dhcpsettings{'KEY2'} = 0;
471: 	} else {
472: 	    @current2[$dhcpsettings{'KEY2'}] = "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n";
473: 	    $dhcpsettings{'KEY2'} = '';       # End edit mode
474: 	    &General::log($Lang::tr{'fixed ip lease modified'});
475:
476: 	    # sort newly added/modified entry
477: 	    &sortcurrent2;
478: 	}

I described these business rules as they were implemented in IPFire a long time agoโ€ฆ

CU202 :

From what I understand of the /usr/sbin/unbound-dhcp-leases-bridge program

At startup
1 - Saves the static addresses from the /var/ipfire/main/hosts file to /etc/unbound/hosts.conf
2 - Saves the assigned DHCP addresses from the /var/state/dhcp/dhcpd.leases file to /etc/unbound/dhcp-leases.conf
3 - Saves the addresses from the /var/ipfire/dhcp/fixleases file to /etc/unbound/dhcp-leases.conf if it is not already declared static in /etc/unbound/hosts.conf

Then
When a host connects via DHCP, it adds its address and hostname to the local_data if they are not already present in /etc/unbound/dhcp-leases.conf.
At the end of the lease DHCP, removes the host from the local_data

CU 203

Based on what I observed for CU203 regarding knot-resolver (I could be wrong. )

At startup
1 - It loads the addresses defined in the /etc/hosts and /var/ipfire/main/hosts files into its local cache.

Then
When a host connects via DHCP, it adds its address and client hostname in other lease.db cache DNS and overwrites the address if defined in hosts is different.
The value of the REMARK field recorded in dhcp.cgi is ignored.

This bad โ€œhostname - addressโ€ record persists in the cache (the cache is retained on disk even after a reboot).

The record is only removed when the DHCP lease is released or expires. However, this does not always happen, so the stale record can remain in leases.db indefinitely unless it is removed manually.

Nice find.

This means we should discuss the construction of the local name space and integration into the DNS โ€˜serverโ€™. This is not unbound/knot dependend. The local name space has three components

  • DNS server for name resolution, using fixed information in hosts file
  • DHCP server for generating (name,IP) relations for local devices
  • Transfer of information from DHCP to DNS

Because a name is optional for a DHCP request by a client, not all devices generate a (name,IP) tuple.
The work-around used until CU203, take the start of the remark as host name, is sufficient and effective if a client supplied host name overwrites this default. This was the case before.

It is possible to supply this default host name in the dhcp config. I think this necessary also, as many users trusted the note in the wiki.

I had some issues and observations on the installation process.

IPFire Pakfire Signing Key was missing after update and required re importing.

The /var/ipfire/red/active file is missing - Required by pakfire for updates and installs. Required creation with โ€œtouch /var/ipfire/red/activeโ€

Dynamic DNS is not resolving after serval hours. Almost a day later the hostnames have resolved.

Initialy the Domain Name System Status was showing Broken, Hours after the upgrade it started Working. Howeever, some of the Nameservers still showed a status of Error. Almost a day later the DNS Servers are reporting a status of OK.

In my opinion, IP addresses that are manually assigned to a hostname in the hosts file should take precedence and always be returned by the local DNS resolver.

For DHCP leases, there is no inherently right or wrong behavior. However, whichever behavior is chosen should be clearly documented in the wiki by the person implementing or changing it.

And if the behavior changes between releases, those changes should also be clearly documented and explained.
Otherwise, users are left trying to figure out why a configuration that worked in one version behaves differently in the next.

This may be a policy

  • defined relations (name,IP) in hosts have highest precedence ( admin/user wants to name a device as NAME )
  • devices joining the IP net are known by the name they introduce themselves ( fixed and dynamic leases in DHCP )
  • devices which decide to remain anonymous, by giving no name, can get a default name defined by fixed leases definition. Dynamic leases have no name in this case.

BTW: The dhcp.conf (in CU203 and former version) defines a host name for each fixed lease, fixnn, but this is not propagated as default to DNS.
CU203 tries to implement the DHCPโ€“>DNS link more straightforward, without the complex unbound-dhcp-leases-bridge program. On this way some features were lost. Unfortunately this was not tested and found in the pre-release period.

From a userโ€™s perspective, it is difficult to understand how behavior that was previously accepted has now become a bug.
If the design has evolved, it would be helpful to explain what changed, why it changed, and from which release the new behavior is considered the intended one.

And yet, that is what I had tried to describe here.

Hi there, I please need help with a question regarding hostname lookup in CU203. I did not define the client names in โ€œhostsโ€ but in the โ€œDHCPโ€ section under โ€œCommentโ€.

leases.db looks like this:

sqlite> SELECT * FROM leases;
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚     address     โ”‚                 hostname                 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ 192.168.xxx.72  โ”‚ wsm.green.mydomain.com.                  โ”‚
โ”‚ 192.168.xxx.19  โ”‚ onkyo-tx-8470-63d5e1.green.mydomain.com. โ”‚
โ”‚ 192.168.yyy.202 โ”‚ ap1.blue.mydomain.com.                   โ”‚
โ”‚ 192.168.yyy.201 โ”‚ apswitch.blue.mydomain.com.              โ”‚
โ”‚ 192.168.xxx.22  โ”‚ nas.green.mydomain.com.                  โ”‚
โ”‚ 192.168.xxx.201 โ”‚ switch.green.mydomain.com.               โ”‚
โ”‚ 192.168.yyy.68  โ”‚ iphone.blue.mydomain.com.                โ”‚
โ”‚ 192.168.yyy.24  โ”‚ nms.blue.mydomain.com.                   โ”‚
โ”‚ 192.168.yyy.203 โ”‚ ap2.blue.mydomain.com.                   โ”‚
โ”‚ 192.168.yyy.69  โ”‚ watch.blue.mydomain.com.                 โ”‚
โ”‚ 192.168.xxx.17  โ”‚ samsung.green.mydomain.com.              โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

It seems to appear that the hostnames are taken from the clients themselfes rather than from the DHCP configuration section.. For example seem โ€œap1โ€, โ€œap2โ€ and โ€œapswitchโ€ to be correct (these hostname are configured within their corresponding settings as well as the same name in their โ€œDHCPโ€ comment sections), whereas, e.g., the fixed/given name โ€œonkyo-tx-8470-63d5e1โ€ is defined as โ€œrcvโ€ in the โ€œDHCPโ€ section.

But - when looking up any hostname on the iPFire shell, e.g.


[root@ipfire ~]# nslookup ap1 
Server:         127.0.0.1 
Address:        127.0.0.1#53 
 
** server can't find ap1: NXDOMAIN

or

[root@ipfire ~]# nslookup nas
Server:         127.0.0.1
Address:        127.0.0.1#53

** server can't find nas: NXDOMAIN

or

[root@ipfire ~]# nslookup onkyo-tx-8470-63d5e1
Server:         127.0.0.1
Address:        127.0.0.1#53

** server can't find onkyo-tx-8470-63d5e1: NXDOMAIN

nslookup (even on iPFire locally) provides no results.

Iโ€™ve defined DHCP starting from 192.168.xxx.8 and 192.168.yyy.8 up to .210 each, and activated โ€œDeny known hostsโ€.

Is this behavior intended and will that change within the next releases? Shall I add the client names to the โ€œhostsโ€ section to get them resolved?

As stated in multiple posts, the REMARKS field isnโ€™t used anymore.
Host names must be supplied by the clients or by the admin in the Hosts WUI page.

In your case, you are using a different domain for each network in the DHCP configuration ( green.mydomain.com and blue.mydomain.com).

Iโ€™m not sure whether this specific DHCP configuration is fully supported by the new DNS resolver. I have done a few quick tests, but I donโ€™t want to clutter this thread with them.
It would be better to investigate this in a separate discussion with more thorough testing.

From what I have observed, it does not work for dynamically assigned DHCP leases. If my suspicion is confirmed, migrating this configuration to CU203 could be more complex, as each client might need to be added to the hosts file with its corresponding domain.

Edit : For dynamically assigned DHCP leases. It looks as though the network-specific domains would also need to be added to /etc/resolv.conf for dynamic hostname resolution to work correctly
This may be a bug, but it needs more testing to confirm

Tests are good to check various application cases, hopefully getting a representive amount.

But in this special case, studying the sources shows the state of DHCP-DNS cooperation:

  • host names are taken from the request packet of the client only
  • domain names are generated based on the interface, configuration is defined in WUI and dhcpd.conf

I am also experiencing this issue. DNS is broken. Iโ€™ve had to manually assign DNS to network devices to allow internet access. I hope it doesnโ€™t take as long as you indicate. Will report back on progress.

With the general usage policy of IPFire โ€œconfig is done by WUIโ€, a solution on the CLI is not recommended.
Each save on a WUI page writes new system config files. A โ€˜.localโ€™ solution isnโ€™t possible with Knot as name resolver.
Therefore name definitions should come from the โ€˜officialโ€™ ways: host definitions(Edit Hosts) and name introduction of a device by DHCP.
Because the default name construct from the โ€˜remarkโ€™ field doesnโ€™t work in CU203 anymore, for devices not introducing themselves remains the โ€˜Edit hostsโ€™ way.

As a temporary fix I revised the dns IPv4 value in the nmconnection config file on each wireguard client. I know I am giving up some protection but at least the clients are now working again.

Iโ€™m just getting around to checking memory usage for CU203 vs CU202. This is a 4GB Protectli device. CU202 averaged about 80% used memory while CU203 is averaging about 65% used. So definitely noticeable. Screenshot below. The upgrade to CU203 happened on 26 Jul.

Did you inspect swap usage?
Because running out of swap may also generate OOMs. But looking at the memory graphs only doesnโ€™t show this problem. Max memory usage (100%-free) in your graph is 92.25% average, with 92.56% current. So CU202 and CU203 both use nearly the whole 4GB, with little space for temporary peaks.

First of all, a positive observation: after upgrading to Core Update 203, memory usage on my IPFire systems is now only about 30% of what it was before. That is a very welcome improvement, so thank you for the work on the move to Knot Resolver.

I have, however, found what appears to be an issue when Knot Resolver is used together with a Keepalived virtual IP address.

My setup consists of two IPFire systems:

  • Primary IPFire: 192.168.222.251

  • Secondary IPFire: 192.168.222.252

  • Keepalived virtual IP: 192.168.222.254

The virtual IP is used as both the default gateway and the primary DNS server for clients on the GREEN network.

The virtual IP is present correctly on the active node:

inet 192.168.222.251/24 scope global green0
inet 192.168.222.254/32 scope global proto keepalived green0

Knot Resolver is listening on:

0.0.0.0:53

The generated configuration contains:

network:
  listen:
    - interface: 0.0.0.0@53

When a client sends a DNS query to the virtual address, the reply is sent from the physical address of the active IPFire system:

nslookup google.com 192.168.222.254

reply from unexpected source: 192.168.222.251#53,
expected 192.168.222.254#53

A query sent directly to 192.168.222.251 works correctly.

It therefore looks as though Knot receives the query on the virtual IP but chooses the primary interface address as the source address for the UDP reply. Clients reject that reply because it does not come from the address they queried.

Most of my normal clients still appear to work because DHCP also provides 1.1.1.1 as a secondary DNS server. Some Docker containers did not recover in the same way and lost DNS resolution completely until I configured them to use 1.1.1.1 directly.

I realise that Keepalived is not a standard IPFire configuration, and I would prefer not to manually edit /etc/knot-resolver/config.yaml, since it is generated by IPFire and may be overwritten.

Would it be possible for IPFire to support this type of setup by generating explicit listening addresses instead of only 0.0.0.0@53? For example, perhaps the resolver could bind explicitly to the physical address and to any configured virtual address, using freebind where necessary so that the backup node can start before it owns the virtual IP.

Alternatively, is there another supported way to make Knot Resolver send DNS replies using the destination address on which the query was received?

The system is currently usable because of the secondary public DNS server, but DNS failover through the Keepalived virtual IP is not working as intended.

Thank you again for the update and especially for the substantial reduction in memory usage.

This problem has also been found when using openvpn or wireguard vpn tunnels.

A bug has been raised for this

https://bugzilla.ipfire.org/show_bug.cgi?id=14030

which is tracking the bug report feedback into upstream knot-resolver.

Personally, I use a DNS redirection rule to the firewall, as described here, for each of my networks (GREEN, BLUE, OpenVPN):

(Adding TCP 853 to DNS services group for DoT)

After upgrading to CU203, I donโ€™t have any DNS issues with keepalived.

Hope this helps.