Intermittent issue with DHCP v4

I'm currently having an issue with OpenWrt and DHCP v4, as of the last 18.0x release I installed on my Ubiquiti ER-Lite 3. It originally seemed to occur in relation to having installed ZeroTier on the device, but even after removing that, it seems to still occur. What will happen is, after an undetermined amount of uptime, the DHCPv4 services will cease functioning, and only IPv6 will work.

I'll include my configuration files:

/etc/config/system


config system
	option hostname 'OpenWrt'
	option timezone 'UTC'
	option ttylogin '0'
	option log_size '64'
	option urandom_seed '0'

config timeserver 'ntp'
	option enabled '1'
	option enable_server '0'
	list server '0.openwrt.pool.ntp.org'
	list server '1.openwrt.pool.ntp.org'
	list server '2.openwrt.pool.ntp.org'
	list server '3.openwrt.pool.ntp.org'

/etc/config/dhcp


config dnsmasq
	option domainneeded '1'
	option localise_queries '1'
	option rebind_protection '1'
	option rebind_localhost '1'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option nonwildcard '1'
	option localservice '1'
	list server '127.0.0.1#5453'
	list server '0::1#5453'
	option noresolv '1'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option dhcpv6 'server'
	option ra 'server'

config dhcp 'wan'
	option interface 'wan'
	option ignore '1'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

config host
	option name 'MrGency'
	option dns '1'
	option mac '00:D8:61:58:83:26'
	option ip '10.0.0.48'

config host
	option name 'Umaro'
	option dns '1'
	option mac '00:1F:D0:D4:3E:AE'
	option ip '10.0.0.156'

/etc/config/firewall

config defaults
	option syn_flood '1'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	option network 'lan'

config zone
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	option network 'wan wan6'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option src_ip 'fc00::/6'
	option dest_ip 'fc00::/6'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config include
	option path '/etc/firewall.user'

config redirect
	option target 'DNAT'
	option src 'wan'
	option dest 'lan'
	option proto 'tcp'
	option src_dport '2305'
	option dest_ip '10.0.0.156'
	option dest_port '22'
	option name 'SSH'

config redirect
	option target 'DNAT'
	option src 'wan'
	option dest 'lan'
	option proto 'tcp udp'
	option src_dport '5938'
	option dest_ip '10.0.0.48'
	option dest_port '5938'
	option name 'TeamViewer'

config redirect
	option target 'DNAT'
	option src 'wan'
	option dest 'lan'
	option proto 'tcp udp'
	option src_dport '64492'
	option dest_ip '10.0.0.156'
	option dest_port '64492'
	option name 'Transmission BT'

config redirect
	option target 'DNAT'
	option src 'wan'
	option dest 'lan'
	option proto 'tcp'
	option src_dport '8243'
	option dest_ip '10.0.0.156'
	option dest_port '8243'
	option name 'Smokeping HTTPS'

config redirect
	option target 'DNAT'
	option src 'wan'
	option dest 'lan'
	option proto 'tcp'
	option src_dport '80'
	option dest_ip '10.0.0.156'
	option dest_port '80'
	option name 'Smokeping HTTP'

config redirect 'adblock_dns_53'
	option name 'Adblock DNS, port 53'
	option src 'lan'
	option proto 'tcp udp'
	option src_dport '53'
	option dest_port '53'
	option target 'DNAT'

config redirect 'adblock_dns_853'
	option name 'Adblock DNS, port 853'
	option src 'lan'
	option proto 'tcp udp'
	option src_dport '853'
	option dest_port '853'
	option target 'DNAT'

config redirect 'adblock_dns_5353'
	option name 'Adblock DNS, port 5353'
	option src 'lan'
	option proto 'tcp udp'
	option src_dport '5353'
	option dest_port '5353'
	option target 'DNAT'

/etc/config/stubby

config stubby 'global'
       option manual '0'
       option trigger 'wan'
       # option triggerdelay '2'
       list dns_transport 'GETDNS_TRANSPORT_TLS'
       option tls_authentication '1'
       option tls_query_padding_blocksize '128'
       # option tls_connection_retries '2'
       # option tls_backoff_time '3600'
       # option timeout '5000'
       # option dnssec_return_status '0'
       option appdata_dir '/var/lib/stubby'
       # option trust_anchors_backoff_time 2500
       # option dnssec_trust_anchors '/var/lib/stubby/getdns-root.key'
       option edns_client_subnet_private '1'
       option idle_timeout '10000'
       option round_robin_upstreams '1'
       list listen_address '127.0.0.1@5453'
       list listen_address '0::1@5453'
       # option log_level '7'
       # option command_line_arguments ''
       # option tls_cipher_list 'EECDH+AESGCM:EECDH+CHACHA20'
       # option tls_ciphersuites 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
       # option tls_min_version '1.2'
       # option tls_max_version '1.3'

# Upstream resolvers are specified using 'resolver' sections.
config resolver
       option address '2620:fe::fe'
       option tls_auth_name 'dns.quad9.net'

config resolver
       option address '2620:fe::9'
       option tls_auth_name 'dns.quad9.net'

config resolver
       option address '9.9.9.9'
       option tls_auth_name 'dns.quad9.net'

config resolver
       option address '149.112.112.112'
       option tls_auth_name 'dns.quad9.net'

Restarting dnsmasq always fixes it.

Anything interesting in the logs?
Is /tmp full by any chance?

Nope. Just checked disk and memory space:

Filesystem                Size      Used Available Use% Mounted on
/dev/root                 1.6G     24.9M      1.5G   2% /
tmpfs                   196.5M    476.0K    196.0M   0% /tmp
tmpfs                   512.0K         0    512.0K   0% /dev

Logs aren’t that useful, because even without the usual lan side dhcp renewal traffic, it gets flooded every 10 minutes by the wan side dhcp renewal. Yes, when I use the fake bridge double-nat mode of my isp’s equipment, it enforces renewal every 10 minutes.

I wish I could set the logging to be a little more useful, since I have 512MB of ram and 1.5GB of writable root to spare.

The thing is that since it is working under normal circumstances, it most likely is not a configuration error. So you'll need to catch it red-handed.
When the issue occurs:

  1. Check if dnsmasq is indeed running (from ps or netstat/ss)
  2. Check logs, filter by greping dnsmasq. You may want to increase verbosity to have more chances of finding something useful.
  3. If the previous points are fine, verify if it is only for a renewal or for new lease as well.

You could increase the buffer size, not to lose something important during logrotate.