OPNsense Gets Its Turn
Is this a good idea? Turns out 🤔…
🤷 Maybe… ?
What the hell is this?! #
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…
- Gabriel Tanner6 wrote up a pretty good walk-thru
- Silvio Vasiljevic7 wrote a great walk-thru on setting up a matrix server8, which includes some turn/stun guidance.
- Our Code World9 had a good walk through on setting up coturn as well.
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 #
root@opnsense# opnsense-code ports
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
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…
root@opnsense# cd /usr/ports/net/sctplib &&make install
This won’t take long tho…
Yep Its time to build coturn! #
root@opnsense# cd /usr/ports/net/turnserver/ && make install clean
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:
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: #
- RFC3489
- “classic” STUN12
- RFC5389
- Base “new” STUN specs13
- RFC5769
- Test vectors for STUN protocol testing14
- RFC5780
- NAT behavior discovery support15
- RFC7443
- ALPN support for STUN & TURN16
- RFC7635
- oAuth third-party TURN/STUN authorization17
- RFC5766
- Base TURN specs18
- RFC6062
- TCP relaying TURN extension19
- RFC6156
- IPv6 extension for TURN20
- RFC7443
- ALPN support for STUN & TURN16
- RFC7635
- oAuth third-party TURN/STUN authorization17
- RFC5245
- ICE21
- RFC5768
- ICE–SIP22
- RFC6336
- ICE–IANA Registry23
- RFC6544
- ICE–TCP24
- RFC5928
- TURN Resolution Mechanism25
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
-
https://community.cisco.com/t5/collaboration-knowledge-base/demystifying-nat-traversal-with-stun-turn-and-ice/ta-p/4766853 ↩︎
-
http://silvio.github.io/docker-matrix/Example.configs.html ↩︎
-
yeah, I’m sure there’s a pun involving shoulders and small feet to be made here… but….. ↩︎