Blocking spammy caller names with VoIP.ms Call Hunting

May 20, 2026

Voip · Sip · Rust · Voip ms · Telephony

I made a small Rust VoIP.ms CNAME blocker.

The short version is that I wanted to block a caller by name instead of by phone number.

This sounds like it should be a normal checkbox somewhere. It is not.

The missing filter

VoIP.ms has a pretty capable CallerID Filtering feature. You can filter on specific caller ID numbers, phone book groups, anonymous callers, calls that do not match the North American number format, STIR/SHAKEN attestation level, and wildcard patterns like area-code-ish blocks.

That is all useful. Unfortunately, it is also very number-shaped.

There are callers where the number is not the stable part. The useful part is the caller ID.

VoIP.ms even has a blog post on stopping spam calls that frames call filtering around numbers, area codes, and anonymous caller status. In the same post, CNAM is described as a way to identify callers before picking up. The Caller ID wiki page also describes incoming Caller ID name lookup as an optional per-DID setting that can display a caller name for US and Canadian callers.

That is helpful! But identifying a caller and filtering a caller are not the same thing.

There is also a VoIP.ms Community Forum thread where someone asked for exactly this: blocking repeated callers by CNAME/CNAM because the caller used a pile of different numbers. A VoIP.ms staff reply said the feature had been suggested before and that there was no ETA.

So, yes, this is apparently not just me being weird. At least not uniquely weird.

The Call Hunting trick

VoIP.ms has another feature called Call Hunting. The normal idea is that a DID can try multiple destinations in order. If the first one does not take the call, the next one gets a shot.

So I made a tool that registers to VoIP.ms as a normal SIP endpoint and sits first in a Call Hunting group. It looks at the incoming caller name and then does one of two things:

  • If the caller does not match the block list, it rejects the call with 486 Busy Here.
  • If the caller matches the block list, it answers, plays SIT tones plus a disconnected-style message, and hangs up.

The 486 Busy Here part is the whole trick. For normal calls, VoIP.ms treats the first destination as busy and keeps going to the next Call Hunting member, which is the real phone path. The blocker gets out of the way.

For blocked calls, the blocker answers the call. Once it answers, the hunt stops. My actual phone never rings.

It’s a bit of a hack, but it is a nice kind of hack. No inbound port forwarding. No PBX to babysit. Just a small SIP endpoint with one job.

Why Twilio Lookup got involved

The original simple version matched the caller name that VoIP.ms delivered in the SIP call.

Then reality did the thing where the one field you want is not the field you get.

For the PCH-style caller I cared about, the VoIP.ms-provided name showed up as a generic city/state-style value. That is not useful enough to block on. Meanwhile, T-Mobile Caller ID showed PCH for the same number.

Searching around for PCH points pretty quickly at Publishers Clearing House, and also at a lot of scam context. PCH has its own scam-report page saying scammers misuse the PCH name to pretend people won prizes and demand money or personal information. The FTC also has an alert specifically about PCH impersonators.

That does not prove T-Mobile and Twilio are using the same database. CNAM is messy enough that I do not want to pretend certainty here. But it did suggest there was a better name source out there than the one I was getting through VoIP.ms.

So I added optional Twilio Lookup support. If configured, the blocker can ask Twilio for the caller name and match against that instead. If Twilio does not return a useful name or the lookup fails, the call is allowed through.

The matching itself is intentionally boring:

BLOCK_CNAME_PATTERNS=pch

Those patterns are case-insensitive and match on token boundaries, so pch can match PCH without accidentally matching some longer unrelated word. There is also a regex option for stranger cases.

The repo

The project is here:

https://github.com/nelsonjchen/cname_blocker_voip

It is not trying to be a complete PBX. It is a narrow little tool:

  • register outbound to VoIP.ms
  • inspect caller name information
  • optionally use Twilio Lookup
  • let normal calls continue through Call Hunting
  • answer only blocked-name calls
  • play a local disconnected message

It is written in Rust, and I deployed it to my TrueNAS box. Resident memory is around 5 MB, which is very satisfying for something that just needs to sit there, stay registered, and be boring until the wrong call shows up.

I also got a lot of it written with Codex 5.4 Medium. This is a good kind of Codex project: small enough to keep in my head, annoying enough that I did not want to hand-type every SIP-shaped detail myself, and testable enough that I could keep it from becoming pure vibes.

The README has the actual setup steps.

The tests do not need real VoIP.ms credentials either. There is a local fake registrar/integration test path that sends matching and non-matching calls, checks that blocked calls get answered, checks that normal calls get 486 Busy Here, and verifies RTP audio makes it through. That made this feel a lot less like a pile of SIP hope.

Anyway, it works for the annoying thing I wanted to stop.

I still think VoIP.ms should offer caller-name filtering directly. Until then, this tiny weird SIP detour is doing the job.