Hi all,
I'm only starting to use IPFire, so apologies if I'm missing some
conventions here. I'm fairly experienced with Linux and firewalls in
general, however.
I found some operations in IPFire unexpectedly slow, in particular
Edit Hosts: every operation, whether changing a host name or just
disabling one, took about five minutes to complete.
The machine in question is rather slow but not *that* slow
(1GHz Via C3, 1GB RAM).
What's more, during that time DNS is broken: ipfire responds to
queries but gives wrong answers, specifically NXDOMAIN for hosts that
do exist. And that was causing problems with my internal mail server.
So I looked at the source.
It turns out that every operation in Edit Hosts triggers
unbound restart, and that's where the time goes:
# time /etc/init.d/unbound restart
[...]
real 4m7.531s
user 1m55.320s
sys 0m7.760s
Looking at the script, this is where it spends most of the time:
update_hosts() {
local enabled address hostname domainname
while IFS="," read -r enabled address hostname domainname; do
[ "${enabled}" = "on" ] || continue
# Build FQDN
local fqdn="${hostname}.${domainname}"
unbound-control -q local_data "${fqdn} ${LOCAL_TTL} IN A ${address}"
# Skip reverse resolution if the address equals the GREEN address
[ "${address}" = "${GREEN_ADDRESS}" ] && continue
# Add RDNS
address=$(ip_address_revptr ${address})
unbound-control -q local_data "${address} ${LOCAL_TTL} IN PTR ${fqdn}"
done < /var/ipfire/main/hosts
}
I have roughly 150 entries in hosts list, so that ends up calling
unbound-control about 300 times. And there's a race condition between
the time unbound is started and when those entries are added (at
different times).
I made the following simple change:
update_hosts() {
local enabled address hostname domainname
while IFS="," read -r enabled address hostname domainname; do
[ "${enabled}" = "on" ] || continue
# Build FQDN
local fqdn="${hostname}.${domainname}"
echo "${fqdn} ${LOCAL_TTL} IN A ${address}"
# Skip reverse resolution if the address equals the GREEN address
[ "${address}" = "${GREEN_ADDRESS}" ] && continue
# Add RDNS
address=$(ip_address_revptr ${address})
echo "${address} ${LOCAL_TTL} IN PTR ${fqdn}"
done < /var/ipfire/main/hosts | unbound-control -q local_datas
}
Result:
# time /etc/init.d/unbound restart
[...]
real 0m15.568s
user 0m4.827s
sys 0m1.403s
So it saves in my case four minutes at every hosts change, every dhcp change,
every boot. Still not blazingly fast but already tolerably so.
That is small and obvious enough change that perhaps it could be
considered for next upgrade (121)?
I can submit it as a patch if that helps.
It's still not a good fix though: it doesn't remove the race condition
window, only shortens it. Rather than using unbound-control to add
local entries it'd be better to put them to a file and include that in
unbound.conf (put the file or two in /etc/unbound/local.d/) so they'd
all take effect immediately when unbound is started. This would be a
bit bigger change but probably not much: if people think it'd be
useful I could give it a go.
Of course it's not actually necessary to restart unbound for every
change in hosts or dhcp at all, they could be effected by making
individual changes with unbound-control, but that would be a much
bigger change (I haven't looked at that part of the code in detail
enough to judge how big). But improving the startup time would be
useful even if that's done at some point.
--
Tapani Tarvainen