DOCSIS DHCP Renewal Fails (Vodafone/ONE) - udhcpc renewals ignored at T1/T2

Hi Everyone,

I'm dealing with a frustrating DHCP renewal issue on my OpenWrt router connected to a DOCSIS cable modem in bridge mode. My ISP is ONE in Hungary (formerly Vodafone / legacy UPC network).

Every 24 hours, my WAN connection drops because the ISP's DHCP server completely ignores my router's renewal requests. It only responds to a brand new DHCP Discover.

The Setup:

  • OpenWrt Version: OpenWrt 25.12.2 r32802-f505120278
  • WAN Interface: wan (IPv4 DHCP Client). IPv6 is disabled as the ISP doesn't support it.
  • Lease Time: 86400 seconds (24 hours).

The Problem: At exactly the 12-hour mark (T1), udhcpc attempts a unicast renewal to the ISP's DHCP server, but it gets ignored. It continues to retry every few hours (T2), but all requests are ignored until the lease finally expires at the 24-hour mark, causing a WAN drop.

Here is the log showing the initial successful connection, followed by the ignored renewals hours later:

Mon Apr 27 16:28:44 2026 daemon.notice netifd: wan (5883): udhcpc: started, v1.37.0
Mon Apr 27 16:28:44 2026 daemon.notice netifd: wan (5883): udhcpc: broadcasting discover
Mon Apr 27 16:28:51 2026 daemon.notice netifd: wan (5883): udhcpc: broadcasting select for 89.x.x.x server 80.x.x.x
Mon Apr 27 16:28:51 2026 daemon.notice netifd: wan (5883): udhcpc: lease of 89.x.x.x obtained from 80.x.x.x, lease time 86400
Tue Apr 28 05:38:21 2026 daemon.notice netifd: wan (5883): udhcpc: sending renew to server 80.x.x.x
Tue Apr 28 11:38:22 2026 daemon.notice netifd: wan (5883): udhcpc: sending renew to server 80.x.x.x
Tue Apr 28 14:38:23 2026 daemon.notice netifd: wan (5883): udhcpc: sending renew to server 80.x.x.x
Tue Apr 28 16:08:23 2026 daemon.notice netifd: wan (5883): udhcpc: sending renew to server 80.x.x.x

What I have already tried (that didn't fix it):

  1. Broadcast Flag: Checked Use broadcast flag in WAN advanced settings.
  2. Client ID (Option 61): Formatted my WAN MAC and added it to Client ID to send when requesting DHCP (e.g., 01xxxxxxxxxxxx - 01 prefix for ethernet type).
  3. Vendor Class: Left empty to avoid looking like an ISP Set-Top Box.
  4. DHCP Server: Checked Ignore interface on the WAN DHCP Server tab so dnsmasq doesn't interfere.

Even with the Broadcast Flag and Client ID, the ISP server drops the unicast renewals. If I manually restart the interface (ifdown wan && ifup wan), it sends a broadcasting discover and immediately gets a lease.

My Current Workaround: Right now, I am using a nightly cron job at 4:00 AM (ifdown wan && sleep 5 && ifup wan) to force a fresh DHCP Discover while I sleep, combined with luci-app-watchcat as a fallback.
Because I run a strict WireGuard VPN killswitch that drops unencrypted ICMP traffic leaving the WAN, standard Watchcat "Restart Interface" mode gets blocked by my firewall. Instead, I configured luci-app-watchcat in "Run Script" mode, bound specifically to my WireGuard interface (proton0 ). It sends 1-byte pings to 1.1.1.1 through the encrypted tunnel. If pings fail for 1 minute (meaning either the ISP lease died or the VPN server stalled), it executes a custom executable script (/sbin/ifdown wan && sleep 5 && /sbin/ifup wan ) to forcefully recover the connection.

My Questions:

  1. Is there any way to force udhcpc to switch to a full DHCP Discover (or broadcast renewal) sooner when unicast renewals fail, instead of waiting for the lease to completely die?
  2. Has anyone else on the ONE/Vodafone/UPC network found a native udhcpc configuration fix for this, or is the ISP's DHCP server just fundamentally broken by blocking T1/T2 renewals?

Logs:

root@OpenWrt:~# ubus call system board
{
        "kernel": "6.12.74",
        "hostname": "OpenWrt",
        "system": "ARMv8 Processor rev 4",
        "model": "Xiaomi Mi Router AX3000T (OpenWrt U-Boot layout)",
        "board_name": "xiaomi,mi-router-ax3000t-ubootmod",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "25.12.2",
                "firmware_url": "https://downloads.openwrt.org/",
                "revision": "r32802-f505120278",
                "target": "mediatek/filogic",
                "description": "OpenWrt 25.12.2 r32802-f505120278",
                "builddate": "1774469393"
        }
}
root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        list ipaddr '127.0.0.1/8'

config globals 'globals'
        option dhcp_default_duid ‘redacted’
        option ula_prefix ‘redacted::/48'
        option packet_steering '2'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'
        list ports 'phy0-ap0'
        list ports 'phy1-ap0'
        option vlan_filtering '1'

config bridge-vlan
        option device 'br-lan'
        option vlan '1'
        list ports 'lan2:u*'
        list ports 'lan3:u*'
        list ports 'phy1-ap0:u*'

config bridge-vlan
        option device 'br-lan'
        option vlan '20'
        list ports 'lan4:u*'

config bridge-vlan
        option device 'br-lan'
        option vlan '30'
        list ports 'phy0-ap0:u*'

config bridge-vlan
        option device 'br-lan'
        option vlan '40'

config interface 'lan'
        option device 'br-lan.1'
        option proto 'static'
        option ipaddr '192.168.0.1'
        option netmask '255.255.255.0'

config device
        option name 'wan'
        option macaddr ‘xx:xx:xx:xx:xx:xx’

config interface 'wan'
        option device 'wan'
        option proto 'dhcp'
        option peerdns '0'
        option multipath 'off'
        list dns '10.2.0.1'
        option broadcast '1'
        option clientid '01xxxxxxxxxxxx’

config interface 'wan6'
        option device 'wan'
        option proto 'dhcpv6'
        option reqaddress 'try'
        option reqprefix 'auto'
        option norelease '1'
        option peerdns '0'
        list dns '2606:4700:4700::1112'
        list dns '2606:4700:4700::1002'
        option multipath 'off'
        option auto '0'
        option disabled '1'

config interface 'proton0'
        option proto 'wireguard'
        option private_key ‘redacted’
        list addresses '10.2.0.2/32'
        list addresses '2a07:b944::2:2/128'
        list dns '10.2.0.1'
        list dns '2a07:b944::2:1'
        option multipath 'off'

config interface 'entertainment'
        option device 'br-lan.20'
        option proto 'static'
        option ipaddr '192.168.20.1'
        option netmask '255.255.255.0'

config interface 'iot'
        option device 'br-lan.30'
        option proto 'static'
        option ipaddr '192.168.30.1'
        option netmask '255.255.255.0'

config interface 'work'
        option device 'br-lan.40'
        option proto 'static'
        option ipaddr '192.168.40.1'
        option netmask '255.255.255.0'

config wireguard_proton0
        option description 'openwrt-HU-34.conf'
        option public_key ‘redacted’
        list allowed_ips '0.0.0.0/0'
        list allowed_ips '::/0'
        option persistent_keepalive '25'
        option endpoint_host '146.70.120.146'
        option endpoint_port '51820'
        option route_allowed_ips '1'
root@OpenWrt:~# cat /etc/config/firewall

config defaults
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'DROP'
        option synflood_protect '1'
        option flow_offloading '1'
        option drop_invalid '1'

config zone
        option name 'lan'
        list network 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        option mtu_fix '1'

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

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

config zone
        option name 'vpn'
        option input 'DROP'
        option output 'ACCEPT'
        option forward 'DROP'
        option masq '1'
        list network 'proton0'

config forwarding
        option src 'lan'
        option dest 'vpn'

config zone
        option name 'entertainment'
        list network 'entertainment'
        option input 'DROP'
        option output 'ACCEPT'
        option forward 'DROP'

config zone
        option name 'iot'
        list network 'iot'
        option input 'DROP'
        option output 'ACCEPT'
        option forward 'DROP'

config zone
        option name 'work'
        list network 'work'
        option input 'DROP'
        option output 'ACCEPT'
        option forward 'DROP'

config forwarding
        option src 'entertainment'
        option dest 'vpn'

config forwarding
        option src 'iot'
        option dest 'vpn'

config forwarding
        option src 'work'
        option dest 'wan'

config rule
        option name 'entertainment-dhcp-dns'
        option src 'entertainment'
        option dest_port '53 67 68'
        option proto 'tcp udp'
        option target 'ACCEPT'

config rule
    option name 'iot-dhcp'
    option src 'iot'
    option dest_port '67 68'
    option proto 'udp'
    option target 'ACCEPT'

config rule
    option name 'iot-dns-cloudflare'
    option src 'iot'
    option dest 'wan'
    option dest_ip '1.1.1.2 1.0.0.2'
    option dest_port '53'
    option proto 'tcp udp'
    option target 'ACCEPT'

config rule
    option name 'iot-block-internal-dns'
    option src 'iot'
    option dest_port '53'
    option proto 'tcp udp'
    option target 'DROP'

config rule
    option name 'work-dhcp'
    option src 'work'
    option dest_port '67 68'
    option proto 'udp'
    option target 'ACCEPT'

config rule
    option name 'work-dns-cloudflare'
    option src 'work'
    option dest 'wan'
    option dest_ip '1.1.1.2 1.0.0.2'
    option dest_port '53'
    option proto 'tcp udp'
    option target 'ACCEPT'

config rule
    option name 'work-block-internal-dns'
    option src 'work'
    option dest_port '53'
    option proto 'tcp udp'
    option target 'DROP'

config rule
        option name 'entertainment-to-jellyfin'
        option src 'entertainment'
        option dest 'lan'
        option dest_ip '192.168.0.222'
        option dest_port '8096'
        option proto 'tcp'
        option target 'ACCEPT'

# --- AirPlay support ---
# mDNS from TV allowed to router for discovery
config rule
    option name 'entertainment-mdns'
    option src 'entertainment'
    option dest_port '5353'
    option proto 'udp'
    option target 'ACCEPT'

config rule
    option name 'lan-mdns'
    option src 'lan'
    option dest_port '5353'
    option proto 'udp'
    option target 'ACCEPT'

# iPhone (LAN) initiating AirPlay connection to TV (Entertainment)
config rule
    option name 'lan-to-tv-airplay'
    option src 'lan'
    option dest 'entertainment'
        option dest_ip '192.168.20.184'
    option dest_port '5000 7000 7001 7100 32768-65535'
    option proto 'tcp'
    option target 'ACCEPT'

config rule
    option name 'lan-to-tv-airplay-udp'
    option src 'lan'
    option dest 'entertainment'
        option dest_ip '192.168.20.184'
    option dest_port '319 320 6002 7000 7010 7011 32768-65535'
    option proto 'udp'
    option target 'ACCEPT'

config rule
    option name 'tv-to-lan-airplay-udp'
    option src 'entertainment'
        option src_ip '192.168.20.184'
    option dest 'lan'
    option dest_port '319 320 32768-65535'
    option proto 'udp'
    option target 'ACCEPT'
root@OpenWrt:~# cat /etc/config/dhcp

config dnsmasq
        option domainneeded '1'
        option boguspriv '1'
        option filterwin2k '0'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option nonegcache '0'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option localservice '1'
        option ednspacket_max '1232'
        option filter_aaaa '0'
        option filter_a '0'
        list server '192.168.0.222'
        list server '192.168.0.200'
        option noresolv '1'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'
        option ra_preference 'medium'
        list dhcp_option '6,192.168.0.222,192.168.0.200'

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

config dhcp 'entertainment'
        option interface 'entertainment'
        option start '100'
        option limit '100'
        option leasetime '12h'

config dhcp 'iot'
        option interface 'iot'
        option start '100'
        option limit '50'
        option leasetime '24h'
        list dhcp_option '6,1.1.1.2,1.0.0.2'

config dhcp 'work'
        option interface 'work'
        option start '100'
        option limit '50'
        option leasetime '8h'
        list dhcp_option '6,1.1.1.2,1.0.0.2'

config odhcpd 'odhcpd'
        option leasefile '/tmp/odhcpd.leases'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'
        option piodir '/tmp/odhcpd-piodir'
        option hostsdir '/tmp/hosts'

config host
        option name ‘server’
        option dns '1'
        list mac ‘xx:xx:xx:xx:xx:xx’
        option ip '192.168.0.111'
        option leasetime 'infinite'

config host
        option name ‘vm’
        option dns '1'
        list mac ‘xx:xx:xx:xx:xx:xx’
        option ip '192.168.0.222'
        option leasetime 'infinite'

config host
        option name ‘vm’
        option dns '1'
        list mac ‘xx:xx:xx:xx:xx:xx’
        option ip '192.168.0.250'
        option leasetime 'infinite'

config host
        option name ‘server’
        option dns '1'
        list mac ‘xx:xx:xx:xx:xx:xx’
        option ip '192.168.0.200'
        option leasetime 'infinite'

config host
        option name ‘device’
        list mac ‘xx:xx:xx:xx:xx:xx’
        option ip '192.168.20.184'
        option leasetime 'infinite'

Thanks in advance for any insights!

Don’t know if it’s related but I had a similar issue with vaderphone in germany.
It turned out, that I need to have anything in the “Vendor Class” field to get it working.
Worth a try …

Thanks for the tip, I'll try setting it as MSFT 5.0 to mimic a Windows PC just to be sure. :slight_smile:
We'll see what happens at the T1/T2 mark tomorrow!

I tried @tomtom 's suggestion of spoofing the Vendor Class (Option 60) to MSFT 5.0 to see if the ISP's DHCP server just needed a recognized client type. It successfully got an initial IP, but the ISP still silently dropped all T1/T2 unicast renewals at the 12-hour mark.

It turns out this is a fundamental routing quirk with the ISP's CMTS (cable modem) in bridge mode. When udhcpc sends a full network broadcast (255.255.255.255), the CMTS intercepts it, tags it as a "Trusted Relay", and the ISP grants the lease. But when udhcpc tries to politely renew via unicast at the 12-hour mark, the packet bypasses the CMTS relay tagging, hits the ISP's DHCP server directly, and gets dropped by their firewall as untrusted.

Instead of using cron jobs to restart the WAN interface (which drops VPN tunnels and active connections), we can use OpenWrt's native nftables (fw4) to silently rewrite the outgoing unicast DHCP renewal into a broadcast packet the millisecond before it leaves the WAN port!

Run these commands via SSH to create a custom firewall hook:

# 1. Create the nftables rule file (no table wrapper needed for fw4 includes)
cat << 'EOF' > /etc/dhcp-renew-fix.nft
chain dhcp_broadcast_fix {
    type nat hook output priority dstnat; policy accept;
    oifname "wan" udp sport 68 udp dport 67 ip daddr != 255.255.255.255 dnat ip to 255.255.255.255
}
EOF

# 2. Tell OpenWrt's firewall to load this file automatically
uci add firewall include
uci set firewall.@include[-1].path='/etc/dhcp-renew-fix.nft'
uci set firewall.@include[-1].type='nftables'
uci set firewall.@include[-1].fw4_compatible='1'
uci commit firewall

# 3. Restart the firewall to activate the rule
/etc/init.d/firewall restart

Because this uses hook output, it only intercepts traffic generated by the router itself (not your LAN). By locking it to udp sport 68 and udp dport 67, it exclusively targets the udhcpc client.

The next time your router attempts a unicast renewal, the firewall instantly changes the destination IP to 255.255.255.255. The ISP's CMTS catches the broadcast, approves the renewal instantly, and your 24-hour lease resets without your WAN interface dropping for even a single second.

Tested and working perfectly. Hope this saves someone else the headache!

Sorry to hear my idea did not help your, but glad to see you found a workaround.
Anyway I’ve stored your solution in a save place, nobody knows about vaderphone’s next ideas.

I hope your current setup keeps working for you, and thanks again for the tip! :slight_smile:

If you ever end up needing to use my workaround, I can happily report that it works flawlessly since:

root@OpenWrt:~ logread | grep -E "udhcpc|netifd: wan "
Thu Apr 30 06:43:44 2026 daemon.notice netifd: wan (6005): udhcpc: sending renew to server 80.x.x.x
Thu Apr 30 06:43:44 2026 daemon.notice netifd: wan (6005): udhcpc: lease of 89.x.x.x obtained from 80.x.x.x, lease time 86400
Thu Apr 30 18:43:44 2026 daemon.notice netifd: wan (6005): udhcpc: sending renew to server 80.x.x.x
Thu Apr 30 18:43:44 2026 daemon.notice netifd: wan (6005): udhcpc: lease of 89.x.x.x obtained from 80.x.x.x, lease time 86400
Fri May  1 06:43:44 2026 daemon.notice netifd: wan (6005): udhcpc: sending renew to server 80.x.x.x
Fri May  1 06:43:44 2026 daemon.notice netifd: wan (6005): udhcpc: lease of 89.x.x.x obtained from 80.x.x.x, lease time 86400

Also, a quick tip I forgot to mention in my original post:

Don't forget to include the custom firewall file in the OpenWrt backup list so it survives system backups and firmware upgrades:

echo "/etc/dhcp-renew-fix.nft" >> /etc/sysupgrade.conf

I am wondering if this is related to:

Which is discussed further here

Both relate to DHCP and Client ID