Chase to main content
  1. Licks, Barks, Howls n Growls from May/

OPNsense Gets Its Turn

😃👋📞🎥📡🛣️🎥📞 😕
Is this a good idea? Turns out 🤔…
🤷 Maybe… ?

What the skwirrel is dad doing?! #

STUN, TURN, and ICE are a set of interrelated protocols and standards which facilitate getting traffic
(usually voip/telephony)
delivered between participats who have different paths to the server(s) in question than they do to each other.

There’s a quite comprehensive overview here, put together by Cisco1

I wanted to see how well a STUN/TURN endpoint for voip-centric nat traversal would work when installed within OPNsense2

There’s a few open source servers that facilitate the functionality.
(notable mention: eTURNal3)
But we chose Coturn 4 5 because reasons™️

Why are we doing it? #

We’d like to be able to use voip tools that are hosted on the inside of our NATed network, with individuals concurrently on either side of the NAT.

Why OPNsense #

Why not?

There’s a few posts out there on doing this on linux hosts…

But there’s surprisingly little information on getting it working within OPNsense10.

I wanted to:

  • See if it would be reasonable to do.

  • See what problems I encountered

  • To document the process

  • and to share my thoughts outcome of the experiment.

So… with the what and the why out of the way…. lets get to it shall we?

Step one… err.. three 😃 #

Sync up the ports tree #

Get the ports tree ready
root@opnsense# opnsense-code ports
Yeah, this is fairly straight forward…

Install some Pre-Requisites and nice-to-haves #

Now lets install some already pre-built packages that we’re gonna need…

And a couple that I just like

Install some pre-compiled prereqs
root@opnsense# pkg install bash cpu-microcode-rc cpustats curl hwstat \
ifinfo iftop jq mtr os-acme-devel os-iperf-devel os-node_exporter-devel \
os-redis-devel os-telegraf-devel pciutils pftop pkgconf psutils screen \
sysinfo tmux vim vnstat wget x86info

Install sctplib #

Coturn has a dependency on sctplib11.

So we’ll have to build it real quick…

Install sctplib
root@opnsense# cd /usr/ports/net/sctplib &&make install

This won’t take long tho…

Yep Its time to build coturn! #

Install coturn
root@opnsense# cd /usr/ports/net/turnserver/ && make install clean
Yeah. I know… Anticlimactic.
So….
Well, cool….
We have coturn installed.
Yay.
uh….
How the hell do we configure it?

For whatever reason, It seems like the required libs to enable prometheus metrics aren’t available. Or, at least, I couldn’t find them easily.
I Admittedly didn’t dig too deeply here as it became evident this wasn’t going to be an enduring solution. Nevertheless, it’s a noteworthy mention

Needful pieces not covered in detail #

There are a few things that you’ll need to set up that’re unrelated to getting coturn working on opnsense.
I’m not gonna cover them in too much detail. Sorry…

SSL Cert
Use acme
(or use a real cert)
DNS A record
Coturn’s FQDN will need to resolve
SRV records
you’ll need to add several DNS srv records for autodiscovery.
Database
coturn supports several database mechanisms.
Pick one.

OPNsense Firewall config #

So, we’ll obviously need to create a few firewall rules….

Make a hole…. Okay… Maybe …. make a smaller hole? #

By default, CoTurn expects to be able to recieve connections to the following ports:

STUN Ports #

TCP/UDP 3478,3479
Unencrypted Listener, and Secondary “alternate” port for Unencrypted listener
TCP/UDP 5349,5350
TLS Listener, and secondary “alternate” port for TLS listener

Proxy Port #

TCP 5555
HAProxy proxy-protocol-v2 compatible listener for reverse-proxying the TCP side

TURN Ports #

UDP 49152-65535
turn uses udp 49152- 65535 by default.

Ratcheting this down to a smaller range, like
UDP 49152-49300
made things much more managable

Prometheus Metrics Port #

TCP 9641
If enabled, Coturn will expose a prometheus exporter on :9641/metrics.

This is a pretty wide range, which can feel a bit unwieldly. Ratcheting the UDP portrange used for TURN makes things a little easier to manage, IMO..

Now that we’ve enumerate what holes we need to cut, lets see what this looks like

OPNsense Rule Categories #

I have a few categories for generic things…

  • TCP
  • UDP
  • ICMP
  • IPv4
  • IPv6
  • PUBLIC
  • INTERNAL
  • EGRESS
  • INBOUND
  • PERMIT
  • BLOCK
  • DROP

I added:

  • TURN
  • STUN

Aliases #

I created the following PORT aliases

STUN_3478 3478

STUN_3479 3479

STUNS_5349 5349

STUNS_5350 5359

STUNS_STUNS_PROXY_5555 5555

TURN_UDP_RELAY 49152 - 49300

STUN_UDP_PORTS
STUN_3478 STUN_3479 STUNS_5349 STUNS_5350
STUN_ALL_TCP_PORTS
STUN_3478 STUN_3479 STUNS_5349 STUNS_5350 STUNS_STUNS_PROXY_5555
STUN_DIRECT_TCP_PORTS
STUN_3478 STUN_3479 STUNS_5349 STUNS_5350
TURN_RELAY_PORTS
TURN_UDP_RELAY
Yeah, I know, these are the same, but the consistency makes rule grokking easier imo..

I created the following HOST aliases

COTURN_EXTERNAL
The public ip coturn listens on: 123.245.123.245
COTURN_INTERNAL
The internal ip coturn listens on 10.10.10.10

And, I created the following NETWORK aliases

INTERNAL_VOIP_NETS
subnets which are allowed to connect to coturn as internal 192.168.100.0/24 192.168.200.0/24
Rules #

External #

Permit ICMP from ANY TO (COTURN_EXTERNAL)

Permit IN IPv4 UDP FROM ANY
TO (COTURN_EXTERNAL) dst port STUN_UDP_PORTS

Permit IN IPv4 TCP FROM ANY
TO (COTURN_EXTERNAL) dst port STUN_DIRECT_TCP_PORTS

Permit IN IPv4 UDP FROM ANY
TO (COTURN_EXTERNAL) dst port TURN_RELAY_PORTS

Permit IN IPv4 TCP FROM ANY
TO (COTURN_EXTERNAL) dst port TURN_RELAY_PORTS

Internal #

Permit ICMP from ANY TO (COTURN_EXTERNAL)

Permit IN IPv4 UDP FROM INTERNAL_VOIP_NETS
TO(COTURN_INTERNAL) dst port STUN_UDP_PORTS

Permit IN IPv4 TCP FROM INTERNAL_VOIP_NETS
TO (COTURN_INTERNAL) dst port STUN_DIRECT_TCP_PORTS

Permit IN IPv4 UDP FROM INTERNAL_VOIP_NETS
TO (COTURN_EXTERNAL) dst port TURN_RELAY_PORTS

Permit IN IPv4 TCP FROM INTERNAL_VOIP_NETS
TO (COTURN_EXTERNAL) dst port TURN_RELAY_PORTS

Coturn Config #

Now that the firewall config is out of the way, we can get to configuring coturn.

I’d encourage you to take a look at Gabriel Tanner6’s walkthru, as it covers the broad strokes fairly well.

  • set the realm you’re going to have coturn handle requests for.
  • set the server-name you want coturn to respond as.
  • adjust the listening ports as necessary
  • fire up coturn and see if things work for you.

So Now what? #

Once I’d gotten this working, I decided I wasn’t really in love with the idea of running coturn on my firewall pair.

I don’t need a TURN server running all the time, and so the juice of persisting this durably wasn’t worth the squeeze to me.

The configuration I ended up with:

  • I set coturn up on an isolated VM in a DMZ.
  • I subsequently configured HAProxy to relay the TCP connections to it.
  • I created port-forward rules for the UDP ports.

Doing this allowed me to image the VM as configured, Restore/reprovision it as/when needed, leaving it offline and unexposed when not in use, as I don’t have a regular need for the functionality.

This was an interesting meander thru some tech I’d not played with before; and I figured it might benefit someone else to document the process I went thru and my findings. I may expand on this more in the future, but for the moment, I’ll leave this here.

Relevant RFCs to read if you’re curious, bored, or have trouble sleeping: #

STUN #

TURN #

ICE #

I’d like to extend sincere gratitude and appreciation for all of the brilliant engineers, developers, and my fellow nerds for allowing me to stand on their shoulders here.

There’s a LOT of complicated stuff going on that these softwares abstract away so that video conferencing tech can work in myriad network environments.

This is no small feat..26 Thanks y’all!

❤️🐺W