The WolfspyreLabs Blog/ 2024/ Posts from May/ OPNsense Gets Its Turn/ 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 # 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 # 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 ↩︎ https://opnsense.org ↩︎ https://eturnal.net ↩︎ https://github.com/coturn/coturn ↩︎ https://gitlab.wolfspyre.io/mirrored_repos/coturn ↩︎ https://gabrieltanner.org/blog/turn-server/ ↩︎ ↩︎ https://github.com/silv-io ↩︎ http://silvio.github.io/docker-matrix/Example.configs.html ↩︎ https://ourcodeworld.com/articles/read/1175/ ↩︎ https://forum.opnsense.org/index.php?topic=11788.0 ↩︎ https://www.nntb.no/~dreibh/sctplib/index.html ↩︎ https://datatracker.ietf.org/doc/html/rfc3489 ↩︎ https://datatracker.ietf.org/doc/html/rfc5389 ↩︎ https://datatracker.ietf.org/doc/html/rfc5769 ↩︎ https://datatracker.ietf.org/doc/html/rfc5780 ↩︎ https://datatracker.ietf.org/doc/html/rfc7443 ↩︎ ↩︎ https://datatracker.ietf.org/doc/html/rfc7635 ↩︎ ↩︎ https://datatracker.ietf.org/doc/html/rfc5766 ↩︎ https://datatracker.ietf.org/doc/html/rfc6062 ↩︎ https://datatracker.ietf.org/doc/html/rfc6156 ↩︎ https://datatracker.ietf.org/doc/html/rfc5245 ↩︎ https://datatracker.ietf.org/doc/html/rfc5768 ↩︎ https://datatracker.ietf.org/doc/html/rfc6336 ↩︎ https://datatracker.ietf.org/doc/html/rfc6544 ↩︎ https://datatracker.ietf.org/doc/html/rfc5928 ↩︎ yeah, I’m sure there’s a pun involving shoulders and small feet to be made here… but….. ↩︎