Yealink desk phones are everywhere on the second-hand market. Operators retire them in batches, resellers list them by the pallet, and they show up on Marktplaats and eBay for a fraction of the new price. The catch is that a lot of those phones are still administratively “owned” by the previous operator, even after a factory reset. In my threat model I want to be able to put my own configuration on a phone I bought, without asking Yealink (or the previous owner’s reseller) for permission. This post explains why that is harder than it sounds, and how multicast SIP PnP lets you do it anyway.

Yealink phones

How “zero-touch provisioning” works

A factory-fresh Yealink phone, on first boot, does not just sit there waiting for a config. It actively goes looking for one. Baked into the firmware are three things: a unique X.509 device certificate (CN=<MAC>, signed by a Yealink CA), a hardcoded RPS hostname (dm.yealink.com, acs.yealink.com or rps.yealink.com depending on firmware generation), and a discovery order that tells the phone which sources to consult. The phone calls home over HTTPS to the RPS hostname, presents its device certificate, and the RPS responds with the URL of the operator’s Device Management Server (DMS). The phone then fetches its config from that DMS and applies it. From that point on the DMS URL is stored locally and used directly on every subsequent boot.

About the “RPS lock”

The RPS database is authoritative for which DMS URL a freshly-reset phone gets sent to. The phone validates the RPS server certificate against a Yealink-bundled trust anchor and not against the public-CA store, so even a Let’s Encrypt cert for the right hostname is rejected. The check is enforced in firmware before any user-supplied config is loaded, so you cannot disable it from outside the device. Changing which DMS a given MAC points to requires a Yealink reseller account. In other words, on the public-internet path the lock holds, and a factory reset sends the phone right back to whichever DMS URL the previous owner’s reseller registered.

Why this matters for resold phones

When you buy a used Yealink, the MAC in Yealink’s RPS database may still point at the old operator’s DMS (dms-tls.kpneen.nl, dms-tls.voipit.nl, and similar). Out of the box the phone phones home to that DMS, presents its factory device cert, and most commonly gets back a 404 because the cert is no longer mapped to an active customer. On rare combinations the phone may even receive a stale config left over from the previous customer. Either way, the phone is not provisioning from you, and a factory reset puts it right back in that state. Without a Yealink reseller relationship you cannot get the registration cleared. Yealink does not offer a self-service “I bought this phone, release it” flow to end users.

The escape hatch: multicast SIP PnP

The RPS lock only affects one step of the discovery sequence. The discovery sequence itself runs first, and on every T4x firmware I have tested (T46S 66.86, T43U 108.86 and 108.87) PnP runs before RPS in the default discovery order. A PnP responder on the phone’s local network can hand the phone a provisioning URL before the phone ever contacts Yealink. The order is configurable via static.auto_provision.boot_discovery.order and defaults have shifted across firmware generations, so verify on the firmware revision you actually have before relying on this.

PnP itself is straightforward. On boot the phone multicasts a SIP SUBSCRIBE for the ua-profile event to 224.0.1.75:5060. Anything on the same L2 segment that replies with a NOTIFY carrying a provisioning URL will be obeyed, with no credentials required, no TLS and no signature on the response body. Whoever answers the multicast SUBSCRIBE first is believed. This is by design: PnP exists so enterprise PBX systems (FreePBX, 3CX, FusionPBX, Asterisk) can claim phones automatically on their own network. From the firmware’s point of view, RPS is not privileged, it is just further down the list. The trust model is “L2 access equals ownership”.

Operational gotchas

A few things are worth knowing before you try this:

  • Same L2 segment. Multicast does not cross VLANs or subnets without IGMP relay. The PnP responder must be on the same broadcast domain as the phone.
  • Host firewall. ufw and firewalld will silently drop the multicast SUBSCRIBE before it reaches the listening socket, so the IGMP join succeeds but the packet never gets delivered. Open UDP/5060 inbound from the phone’s subnet, and TCP on whichever port serves the cfg.
  • PnP may be disabled. PnP fires once per boot when static.auto_provision.pnp_enable = 1 and it is enabled by default and fires before RPS by default. If anyone has set pnp_enable = 0, or changed the boot_discovery.order then this tool does not work.

So PnP does not unlock RPS, it routes around it. The lock is still there in firmware, but the discovery order simply renders it unreachable on the firmware revisions tested. For a second-hand T4x with an unknown RPS registration history, this is the most direct way to reclaim the phone without a Yealink reseller relationship.

To make this practical I wrote a small Go orchestrator around the PnP handshake, called yealink-magician. You point it at the phone’s IP and a .cfg file, factory-reset the phone, and at next boot the magician answers the multicast SUBSCRIBE with a NOTIFY pointing at its own embedded HTTP server. The phone fetches the cfg, applies it, and reboots. Optionally you can pass a .rom firmware file and the same run will also reflash the phone (with full HTTP Range support, since the phone pulls the rom in chunks). It filters by source IP, so two phones resetting at the same time on the same segment do not cross-talk. You can find the source on my GitHub repository, see:

https://github.com/mevdschee/yealink-magician

Have fun!