Skip to content

Commit 5b2f7e9

Browse files
authored
Change name to Rel, add proper README (#9)
* Change project name to `Rel` * Update README.md * Add badges to README.md * Add information about CORS to README.md, update references
1 parent 6eb2255 commit 5b2f7e9

26 files changed

+190
-77
lines changed

Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ RUN apk add --no-cache --update libncursesw openssl libstdc++
2828

2929
WORKDIR /app
3030

31-
COPY --from=build /app/_build/prod/rel/ex_turn ./
31+
COPY --from=build /app/_build/prod/rel/rel ./
3232

33-
CMD ["bin/ex_turn", "start"]
33+
CMD ["bin/rel", "start"]

README.md

+117-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,119 @@
1-
# ExTURN
1+
# Rel
22

3-
TURN server.
3+
[![CI](https://img.shields.io/github/actions/workflow/status/elixir-webrtc/rel/ci.yml?logo=github&label=CI)](https://github.com/elixir-webrtc/rel/actions/workflows/ci.yml)
4+
[![CI](https://img.shields.io/github/actions/workflow/status/elixir-webrtc/rel/build_deploy.yml?logo=github&label=CI)](https://github.com/elixir-webrtc/rel/actions/workflows/build_deploy.yml)
5+
[![Package](https://ghcr-badge.egpl.dev/elixir-webrtc/rel/latest_tag?trim=major&label=latest)](https://github.com/elixir-webrtc/rel/pkgs/container/rel)
6+
7+
TURN server in pure Elixir.
8+
9+
Aims to implement:
10+
- [RFC 5766](https://datatracker.ietf.org/doc/html/rfc5766)
11+
- [RFC 6156](https://datatracker.ietf.org/doc/html/rfc6156#autoid-7)
12+
13+
This project is in early stage of development and some of the features described in the RFCs might be missing.
14+
Expect breaking changes.
15+
16+
Supports authentication described in [A REST API For Access To TURN Services](https://datatracker.ietf.org/doc/html/draft-uberti-rtcweb-turn-rest-00#section-2.2).
17+
18+
## Public deployment
19+
20+
If you're in need of TURN server for testing purposes, feel free to use this Rel public deployment at `turn.bigcow.ovh`.
21+
22+
In case of any irregularities or bugs, please open an issue with description of the problem.
23+
DO NOT use this deployment in production, as it's intended to be an aid in developement only.
24+
25+
To obtain a set of credentials, use the built-in credentials mechanism. It does not require any authentication, but the credentials must be refreshed after 3 hours if not used.
26+
27+
```console
28+
$ curl -X POST "https://turn.bigcow.ovh/?service=turn&username=johnsmith"
29+
{"password":"l6hs9SzUgudFeb5XjrfCfOWKeOQ=","ttl":1728,"uris":["turn:167.235.241.140:3478?transport=udp"],"username":"1691574817:johnsmith"}⏎
30+
```
31+
32+
Use the obtained credentials in e.g. WebRTC's `RTCPeerConnection`:
33+
34+
```js
35+
pc = new RTCPeerConnection({
36+
iceServers: [
37+
{
38+
credential: "l6hs9SzUgudFeb5XjrfCfOWKeOQ=",
39+
urls: "turn:167.235.241.140:3478?transport=udp",
40+
username: "1691574817:johnsmith"
41+
}
42+
]
43+
});
44+
```
45+
46+
## Installation
47+
48+
1. From source
49+
50+
```console
51+
git clone https://github.com/elixir-webrtc/rel.git
52+
cd rel
53+
mix deps.get
54+
mix run --no-halt
55+
```
56+
57+
2. In Docker
58+
59+
```console
60+
docker run ghcr.io/webrtc-elixir/rel:latest
61+
```
62+
63+
## Features and configuration
64+
65+
Currently, Rel is configured via environment variables.
66+
67+
### TURN server
68+
69+
Rel by default listens on `0.0.0.0:3478/UDP` for TURN traffic. This can be configured via `LISTEN_IP` and `LISTEN_PORT`.
70+
71+
```console
72+
LISTEN_IP=0.0.0.0
73+
LISTEN_PORT=3478
74+
```
75+
76+
`EXTERNAL_LISTEN_IP` is the IP address at which Rel is visible to clients. By default, Rel will try to guess the address
77+
based on active network interfaces, but this must be set explicitly when e.g. using Docker without `--network host`.
78+
79+
```console
80+
EXTERNAL_LISTEN_IP=167.235.241.140
81+
```
82+
83+
By default, Rel will use the same addresses (`RELAY_IP == LISTEN_IP and EXTERNAL_RELAY_IP == EXTERNAL_LISTEN_IP`) to open allocations, but this
84+
can be set to something else:
85+
86+
```console
87+
RELAY_IP=0.0.0.0
88+
EXTERNAL_RELAY_IP=167.235.241.140
89+
```
90+
91+
Remember to use the `DOMAIN_NAME` variable specific to your deployment. It's used in e.g. `SOFTWARE` STUN attributes.
92+
93+
```console
94+
DOMAIN_NAME=my-amazing-turn.com
95+
```
96+
97+
### Auth
98+
99+
Auth Provider is an HTTP endpoint that provides credentials required by *A REST API For Access To TURN Services*.
100+
By default it is available at `http://127.0.0.1:4000/`, but the address, encryption and CORS can be configured:
101+
102+
```console
103+
AUTH_PROVIDER_IP=127.0.0.1
104+
AUTH_PROVIDER_PORT=4000
105+
AUTH_PROVIDER_USE_TLS=false
106+
KEY_FILE_PAHT=./rel.key
107+
CERT_FILE_PATH./rel.cert
108+
AUTH_PROVIDER_ALLOW_CORS=false
109+
```
110+
111+
### Metrics
112+
113+
By default, Rel provides Prometheus metrics at `http://127.0.0.1:9578/metrics`. The address can be configured:
114+
115+
```console
116+
METRICS_IP=127.0.0.1
117+
METRICS_PORT=9568
118+
```
4119

5-
Implementation of [RFC 5766](https://datatracker.ietf.org/doc/html/rfc5766) and [RFC 6156](https://datatracker.ietf.org/doc/html/rfc6156#autoid-7).
6-
Supports authentication described in [A REST API For Access to TURN Services](https://datatracker.ietf.org/doc/html/draft-uberti-rtcweb-turn-rest-00).

config/config.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Config
22

3-
config :ex_turn,
3+
config :rel,
44
# 1 day in seconds, see https://datatracker.ietf.org/doc/html/draft-uberti-rtcweb-turn-rest-00#section-2.2
55
credentials_lifetime: 24 * 60 * 60,
66
# 10 minutes in seconds

config/prod.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import Config
22

33
# FIXME: temporary, as `:credentials_lifetime` is a compile time variable atm
4-
config :ex_turn, :credentials_lifetime, 3 * 24 * 24
4+
config :rel, :credentials_lifetime, 3 * 24 * 24

config/runtime.exs

+4-4
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ external_relay_ip =
107107
end
108108

109109
# AuthProvider/credentials configuration
110-
config :ex_turn,
110+
config :rel,
111111
auth_provider_ip:
112112
System.get_env("AUTH_PROVIDER_IP", "127.0.0.1") |> ConfigUtils.parse_ip_address(),
113113
auth_provider_port: System.get_env("AUTH_PROVIDER_PORT", "4000") |> ConfigUtils.parse_port(),
@@ -118,7 +118,7 @@ config :ex_turn,
118118
certfile: certfile
119119

120120
# TURN server configuration
121-
config :ex_turn,
121+
config :rel,
122122
listen_ip: listen_ip,
123123
external_listen_ip: external_listen_ip,
124124
relay_ip: relay_ip,
@@ -127,11 +127,11 @@ config :ex_turn,
127127
domain_name: System.get_env("DOMAIN_NAME", "example.com")
128128

129129
# Metrics endpoint configuration
130-
config :ex_turn,
130+
config :rel,
131131
metrics_ip: System.get_env("METRICS_IP", "127.0.0.1") |> ConfigUtils.parse_ip_address(),
132132
metrics_port: System.get_env("METRICS_PORT", "9568") |> ConfigUtils.parse_port()
133133

134134
# Automatically generated secrets
135-
config :ex_turn,
135+
config :rel,
136136
auth_secret: :crypto.strong_rand_bytes(64),
137137
nonce_secret: :crypto.strong_rand_bytes(64)

docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: '3.2'
22
services:
33
turn:
4-
image: ghcr.io/elixir-webrtc/ex_turn:${TAG}
4+
image: ghcr.io/elixir-webrtc/rel:${TAG}
55
container_name: turn
66
restart: on-failure
77
network_mode: host

lib/ex_turn/allocation_handler.ex lib/rel/allocation_handler.ex

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.AllocationHandler do
1+
defmodule Rel.AllocationHandler do
22
@moduledoc false
33
use GenServer, restart: :transient
44

@@ -7,15 +7,15 @@ defmodule ExTURN.AllocationHandler do
77
alias ExSTUN.Message
88
alias ExSTUN.Message.Type
99

10-
alias ExTURN.Auth
11-
alias ExTURN.Attribute.{ChannelNumber, Data, Lifetime, XORPeerAddress}
12-
alias ExTURN.Utils
10+
alias Rel.Auth
11+
alias Rel.Attribute.{ChannelNumber, Data, Lifetime, XORPeerAddress}
12+
alias Rel.Utils
1313

1414
@type five_tuple() ::
1515
{:inet.ip_address(), :inet.port_number(), :inet.ip_address(), :inet.port_number(), :udp}
1616

17-
@permission_lifetime Application.compile_env!(:ex_turn, :permission_lifetime)
18-
@channel_lifetime Application.compile_env!(:ex_turn, :channel_lifetime)
17+
@permission_lifetime Application.compile_env!(:rel, :permission_lifetime)
18+
@channel_lifetime Application.compile_env!(:rel, :channel_lifetime)
1919

2020
@spec start_link(term()) :: GenServer.on_start()
2121
def start_link([five_tuple, alloc_socket | _rest] = args) do

lib/ex_turn/attributes/additional-address-family.ex lib/rel/attributes/additional-address-family.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.AdditionalAddressFamily do
1+
defmodule Rel.Attribute.AdditionalAddressFamily do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/channel_number.ex lib/rel/attributes/channel_number.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.ChannelNumber do
1+
defmodule Rel.Attribute.ChannelNumber do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/data.ex lib/rel/attributes/data.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.Data do
1+
defmodule Rel.Attribute.Data do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/even_port.ex lib/rel/attributes/even_port.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.EvenPort do
1+
defmodule Rel.Attribute.EvenPort do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/lifetime.ex lib/rel/attributes/lifetime.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.Lifetime do
1+
defmodule Rel.Attribute.Lifetime do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/requested_address_family.ex lib/rel/attributes/requested_address_family.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.RequestedAddressFamily do
1+
defmodule Rel.Attribute.RequestedAddressFamily do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/requested_transport.ex lib/rel/attributes/requested_transport.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.RequestedTransport do
1+
defmodule Rel.Attribute.RequestedTransport do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/reservation_token.ex lib/rel/attributes/reservation_token.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.ReservationToken do
1+
defmodule Rel.Attribute.ReservationToken do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/attributes/xor_peer_address.ex lib/rel/attributes/xor_peer_address.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.XORPeerAddress do
1+
defmodule Rel.Attribute.XORPeerAddress do
22
@moduledoc """
33
STUN Message Attribute XOR Peer Address
44

lib/ex_turn/attributes/xor_relayed_address.ex lib/rel/attributes/xor_relayed_address.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.Attribute.XORRelayedAddress do
1+
defmodule Rel.Attribute.XORRelayedAddress do
22
@moduledoc false
33
@behaviour ExSTUN.Message.Attribute
44

lib/ex_turn/auth.ex lib/rel/auth.ex

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
defmodule ExTURN.Auth do
1+
defmodule Rel.Auth do
22
@moduledoc false
33
require Logger
44

55
alias ExSTUN.Message
66
alias ExSTUN.Message.Attribute.{MessageIntegrity, Nonce, Realm, Username}
77

8-
@nonce_lifetime Application.compile_env!(:ex_turn, :nonce_lifetime)
9-
@credentials_lifetime Application.compile_env!(:ex_turn, :credentials_lifetime)
8+
@nonce_lifetime Application.compile_env!(:rel, :nonce_lifetime)
9+
@credentials_lifetime Application.compile_env!(:rel, :credentials_lifetime)
1010

1111
@spec authenticate(Message.t(), username: String.t()) :: {:ok, binary()} | {:error, atom()}
1212
def authenticate(%Message{} = msg, opts \\ []) do
13-
auth_secret = Application.fetch_env!(:ex_turn, :auth_secret)
13+
auth_secret = Application.fetch_env!(:rel, :auth_secret)
1414

1515
with :ok <- verify_message_integrity(msg),
1616
{:ok, username, nonce} <- verify_attrs_presence(msg),
@@ -64,7 +64,7 @@ defmodule ExTURN.Auth do
6464
|> :base64.decode()
6565
|> String.split(" ", parts: 2)
6666

67-
nonce_secret = Application.fetch_env!(:ex_turn, :nonce_secret)
67+
nonce_secret = Application.fetch_env!(:rel, :nonce_secret)
6868

6969
is_hash_valid? = hash == :crypto.hash(:sha256, "#{timestamp}:#{nonce_secret}")
7070

@@ -77,7 +77,7 @@ defmodule ExTURN.Auth do
7777
@spec generate_credentials(String.t() | nil) ::
7878
{username :: String.t(), password :: String.t(), ttl :: non_neg_integer()}
7979
def generate_credentials(username \\ nil) do
80-
auth_secret = Application.fetch_env!(:ex_turn, :auth_secret)
80+
auth_secret = Application.fetch_env!(:rel, :auth_secret)
8181
timestamp = System.os_time(:second) + @credentials_lifetime
8282

8383
username = if is_nil(username), do: "#{timestamp}", else: "#{timestamp}:#{username}"

lib/ex_turn/auth_provider.ex lib/rel/auth_provider.ex

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule ExTURN.AuthProvider do
1+
defmodule Rel.AuthProvider do
22
@moduledoc false
33
# REST service described in https://datatracker.ietf.org/doc/html/draft-uberti-rtcweb-turn-rest-00
44
defmodule ConditionalCORSPlug do
@@ -8,7 +8,7 @@ defmodule ExTURN.AuthProvider do
88
def init(_opts), do: []
99

1010
def call(conn, _opts) do
11-
allow? = Application.fetch_env!(:ex_turn, :auth_provider_allow_cors?)
11+
allow? = Application.fetch_env!(:rel, :auth_provider_allow_cors?)
1212

1313
if allow? do
1414
CORSPlug.call(conn, CORSPlug.init([]))
@@ -22,7 +22,7 @@ defmodule ExTURN.AuthProvider do
2222

2323
require Logger
2424

25-
alias ExTURN.Auth
25+
alias Rel.Auth
2626

2727
plug(ConditionalCORSPlug)
2828
plug(:match)
@@ -37,8 +37,8 @@ defmodule ExTURN.AuthProvider do
3737
username = Map.get(query_params, "username")
3838
{username, password, ttl} = Auth.generate_credentials(username)
3939

40-
ip_addr = Application.fetch_env!(:ex_turn, :external_listen_ip)
41-
port = Application.fetch_env!(:ex_turn, :listen_port)
40+
ip_addr = Application.fetch_env!(:rel, :external_listen_ip)
41+
port = Application.fetch_env!(:rel, :listen_port)
4242

4343
response =
4444
Jason.encode!(%{

0 commit comments

Comments
 (0)