Sign inSign up

ulfrasark/olcrtc

By ulfrasark

Updated 20 days ago

olcRTC tunnel server for MikroTik RouterOS containers

Image
Networking
Security
0

190

ulfrasark/olcrtc repository overview

olcRTC tunnel server for MikroTik RouterOS containers.

Patched build of openlibrecommunity/olcrtc — tunnels TCP/UDP traffic through public video-conferencing platforms (Telemost / Jitsi / WBStream) by disguising it as a WebRTC video call. Pairs with the WireTurn Android client.

Built from source on every push. Config-file driven: drop one or more *.yaml in the mount directory and the container brings up a separate olcRTC process for each.


What's changed vs upstream

This image is not vanilla olcRTC. Four patches are applied at build time to make the Telemost provider actually work from a datacenter/RouterOS container and to make client pairing painless. Upstream (as of this build) does not carry them.

#PatchWhy
1X-Telemost-Client-Version bumped 187.1.0207.3.0 + fresh User-AgentYandex raised the minimum client version; old value gets rejected. Override with --build-arg TELEMOST_CLIENT_VERSION=...
2+3HTTP/2 disabled in the HTTP client (ForceAttemptHTTP2=false, empty TLSNextProto) + ALPN pinned to http/1.1 in the TLS configcloud-api.yandex.ru negotiates HTTP/2 but sends a broken SETTINGS frame → connection reset → the auth request never reaches the API. Forcing HTTP/1.1 (like a browser) fixes it. This was the real blocker — the error surfaces misleadingly as auth provider rejected ... 400.
4Server prints a ready-to-copy client URI to the log on connectThe vp8channel frame token is derived from the room string. If the server config uses the full room URL and the client uses the bare ID, tokens mismatch and no data flows. The logged URI carries the exact same room string the server used, so client pairing can't drift.

Plus: GODEBUG=http2client=0 is exported in the entrypoint as a belt-and-suspenders HTTP/2 kill-switch, the entrypoint self-restarts a crashed process inside the container (so RouterOS doesn't restart-storm and take down neighbouring containers), and curl is bundled for in-container debugging.

Full write-up of the reverse-engineering path is in PATCH_NOTES.md in the build context.


Tags
TagNotes
latestNewest build
uriAdds patch 4 (client URI printed to log)
h2fixAdds patches 2+3 (HTTP/2 disabled + ALPN pin) — the fix that made Telemost connect
v1Initial patched build (version bump only)

RouterOS caches images by name:tag. When updating, build under a new tag and give the container a new root-dir, otherwise the old layer is reused.


How it works
  • Place one or more server.<provider>.<transport>.yaml files in the mount directory (/etc/olcrtc inside the container).
  • The container scans for *.yaml / *.yml and starts one olcRTC process per file — so several rooms / providers / users can run side by side.
  • On connect, each process logs a WireTurn client URI line — copy that straight into the client.
  • The server joins the video room as a fake participant (random name). The client joins the same room; traffic rides the WebRTC media between them.

Recommended combo for stealth: Telemost + vp8channel (below). For raw speed with less stealth: Jitsi + datachannel.


Example config

server.telemost.vp8channel.yaml — Telemost carrier, VP8 steganography transport:

mode: srv
auth:
  provider: telemost
room:
  # Create a meeting at telemost.yandex.ru and paste its link (or bare ID).
  # Whatever form you use here is echoed back in the logged client URI.
  id: "https://telemost.yandex.ru/j/PUT_ROOM_ID_HERE"
crypto:
  # 64 hex chars (32 bytes). Generate: openssl rand -hex 32
  # Same key must be used by the client.
  key: "PUT_64_HEX_KEY_HERE"
net:
  transport: vp8channel
  dns: "8.8.8.8:53"          # must be a DNS server the container can actually reach
liveness:
  interval: 10s
  timeout: 15s
  failures: 4
vp8:
  fps: 30
  batch_size: 64
debug: false

Prefer keeping the key out of the file? Replace the crypto block with:

crypto:
  key_file: "/etc/olcrtc/olcrtc.key"   # 64 hex chars, one line, same dir

Jitsi alternative (server.jitsi.datachannel.yaml) — no Yandex API, faster, less stealthy:

mode: srv
auth:
  provider: jitsi
room:
  id: "https://meet.jit.si/YourRoomName"
crypto:
  key: "PUT_64_HEX_KEY_HERE"
net:
  transport: datachannel
  dns: "8.8.8.8:53"
liveness:
  interval: 10s
  timeout: 15s
  failures: 4
debug: false

MikroTik setup
1. Network
/interface/veth add name=veth-olc address=172.16.182.2/24 gateway=172.16.182.1
/ip/address add address=172.16.182.1/24 interface=veth-olc
/ip/firewall/nat/add chain=srcnat src-address=172.16.182.0/24 \
  action=masquerade comment="olcrtc container out"
2. Mount
/container/mounts/add name=olc_config src=/docker/olc-confs dst=/etc/olcrtc

Place your server.*.yaml (and optional olcrtc.key) in /docker/olc-confs/ before starting.

3. Install container
/container/add \
  remote-image=ulfrasark/olcrtc:latest \
  interface=veth-olc \
  root-dir=disk1/docker/olcrtc \
  mounts=olc_config \
  dns=8.8.8.8 \
  logging=yes \
  start-on-boot=yes \
  restart-policy=on-failure restart-interval=60s

The entrypoint restarts a crashed olcRTC process internally, so on-failure with a long interval is enough — the whole container almost never needs bouncing, and neighbours stay safe.

4. Enable container mode (x86 CHR)
/system/device-mode/update container=yes

Confirm with a cold reboot (power off + power on via your VPS control panel).

5. Start
/container/start [find tag~"olcrtc"]

Firewall — Telemost domains

Telemost's signaling / STUN / TURN / media servers are reached by these hostnames. If you block Yandex on the container's outbound path, allow these domains (all ports — WebRTC media uses ephemeral UDP ports, not just 3478/443). You do not need to open all of Yandex.

cloud-api.yandex.ru        # HTTP API — conference auth (TCP 443)
goloom.strm.yandex.net     # media signaling — WebSocket (TCP 443)
stun.rtc.yandex.net        # STUN (UDP 3478)
turn.tel.yandex.net        # TURN relay (UDP/TCP 3478, 443 + relayed media)

On RouterOS, add them to an address-list by hostname — RouterOS resolves each name and keeps the resolved IPs in the list:

/ip/firewall/address-list add list=yandex_telemost address=cloud-api.yandex.ru
/ip/firewall/address-list add list=yandex_telemost address=goloom.strm.yandex.net
/ip/firewall/address-list add list=yandex_telemost address=stun.rtc.yandex.net
/ip/firewall/address-list add list=yandex_telemost address=turn.tel.yandex.net

/ip/firewall/filter/add chain=forward src-address=172.16.182.0/24 \
  dst-address-list=yandex_telemost action=accept place-before=0

RouterOS expands a hostname in an address-list only to the IPs it resolves at add time (and on DNS refresh). These Yandex names sit behind CNAME chains and rotate across several IPs, so the list can lag reality and you may see occasional media timeouts on a fresh IP. If that happens, re-resolve (/ip/dns/cache/flush) or, for a rock-solid setup, allow the underlying media subnets instead: 37.9.64.0/18, 77.88.0.0/18, 87.250.224.0/19, 213.180.192.0/19.

Not needed for the Jitsi provider.


Client (WireTurn, Android)

Copy the olcrtc://... URI straight from the server log:

/log/print where topics~"container"

Look for the WireTurn client URI line and import it into WireTurn. Because that URI carries the server's exact room string, the vp8channel frame tokens are guaranteed to match — no token mismatch.


Check logs
/log/print where topics~"container"

Healthy Telemost startup ends with Link connected, the client URI block, then got new track once media flows.


GitHub

Upstream project: openlibrecommunity/olcrtc Android client: spkprsnts/WireTurn

Tag summary

Content type

Image

Digest

sha256:f8f654d8d

Size

17 MB

Last updated

20 days ago

docker pull ulfrasark/olcrtc:v5