Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
galene
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
galene
Commits
5a7937b1
Commit
5a7937b1
authored
Jan 18, 2021
by
Juliusz Chroboczek
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add built-in TURN server.
parent
a15915e8
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
322 additions
and
84 deletions
+322
-84
README
README
+89
-84
galene.go
galene.go
+9
-0
go.mod
go.mod
+1
-0
ice/ice.go
ice/ice.go
+4
-0
turnserver/turnserver.go
turnserver/turnserver.go
+219
-0
No files found.
README
View file @
5a7937b1
...
...
@@ -15,85 +15,6 @@ This step is optional.
echo 'god:topsecret' > data/passwd
## Set up an ICE server
ICE is the NAT and firewall traversal protocol used by WebRTC. ICE uses
a variety of techniques for establishing a flow in the presence of
a firewall; the two most effective techniques, STUN and TURN, require help
from an external server. Whether you need a helping server depends both
on your firewalling setup and on the networks of your users; for
production use, you should probably use your own TURN server.
### No ICE server
If Galène is not firewalled (high-numbered ports are accessible from the
Internet) and none of your users are on a restrictive network, then you
need no ICE servers. There is nothing to do, skip to *Set up a group*
below.
### STUN server
If Galène might be behind a firewall (high-numbered ports might or might
not be accessible from the Internet), but none of your clients are on
a restrictive network, then a STUN server is enough. It is usually safe
to use a third-party STUN server, although doing that might violate the
privacy of your users. Your `data/ice-servers.json` file should look like
this:
[
{
"urls": [
"stun:stun.example.org"
]
}
]
### TURN server
In practice, some of your users will be on restrictive networks: many
enterprise networks only allow outgoing TCP to ports 80 and 443;
university networks tend to additionally allow outgoing traffic to port
1194. For best performance, your TURN server should be located close to
Galène and close to your users, so you will want to run your own. If you
use *coturn*, your `/etc/turnserver.conf` could look like this:
listening-port=443
lt-cred-mech
user=galene:secret
realm=galene.example.org
syslog
Your `ice-servers.json` should look like this:
[
{
"urls": [
"turn:turn.example.org:443",
"turn:turn.example.org:443?transport=tcp"
],
"username": "galene",
"credential": "secret"
}
]
If you prefer to use coturn's `use-auth-secret` option, then your
`ice-servers.json` should look like this:
[
{
"urls": [
"turn:turn.example.com:443",
"turn:turn.example.com:443?transport=tcp"
],
"username": "galene",
"credential": "secret",
"credentialType": "hmac-sha1"
}
]
For redundancy, you may set up multiple TURN servers, and ICE will use the
first one that works.
## Set up a group
A group is set up by creating a file `groups/name.json`.
...
...
@@ -115,10 +36,7 @@ A group with one operator and two users looks like this:
"op": [{"username": "jch", "password": "1234"}],
"presenter": [
{"username": "mom", "password": "0000"},
{
"username": "dad",
"password": "Pójdźże, kiń tę chmurność w głąb flaszy!"
}
{"username": "dad", "password": "1234"}
]
}
...
...
@@ -138,6 +56,27 @@ that the relay test has been successful. (The relay test will fail if you
didn't configure a TURN server; this is normal, and nothing to worry
about.)
## Configure your server's firewall
If your server has a global IPv4 address and there is no firewall, there
is nothing to do.
If your server has a global IPv4 address, then the firewall must, at
a strict minimum, allow incoming traffic to TCP port 8443 (or whatever is
configured with the `-http` command-line option) and TCP port 1194 (or
whatever is configured with the `-turn` command-line option). For best
performance, it should also allow UDP traffic to the TURN port and UDP
traffic to ephemeral (high-numbered) ports.
If your server only has a global IPv6 address, then you should probably
disable the built-in TURN server (`-turn ""`) and configure an external
TURN server; see "ICE Servers" below.
If your server is behind NAT, then you should configure your NAT device to
forward, at a minimum, ports 8443 and 1194. In addition, you should add
the option `-turn 192.0.2.1:1194` to Galène's command line, where `192.0.2.1`
is your NAT's external (global) IPv4 address.
## Deploy to your server
Set up a user *galene* on your server, then do:
...
...
@@ -298,4 +237,70 @@ user entry with a hashed password looks like this:
}
}
--- Juliusz Chroboczek <https://www.irif.fr/~jch/>
# ICE Servers
ICE is the NAT and firewall traversal protocol used by WebRTC. ICE can
make use of two kinds of servers to help with NAT traversal: STUN servers,
that simply help punching holes in NATs, and TURN servers, that serve as
relays for traffic. TURN is a superset of NAT: no STUN server is
necessary if a TURN server is available.
Galène includes a simple IPv4-only TURN server, which is controlled by the
`-turn` command-line option. If the value of this option is the empty
string `""`, then the built-in server is disabled. If the value of this
option is a colon followed with a port number `:1194`, then the TURN
server will listen on all public IPv4 addresses of the local host, over
UDP and TCP. If the value of this option is a socket address, such as
`192.0.2.1:1194`, then the TURN server will listen on all addresses of the
local host but assume that the address seen by the clients is the one
given in the option; this is the recommended configuration when running
behind NAT with port forwarding.
Some users may prefer to disable Galène's built in TURN server (`-turn ""`)
and configure an external ICE server. In that case, the ICE configuration
should appear in the file `data/ice-servers.json`. In the case of a STUN
server, it should look like this:
[
{
"urls": [
"stun:stun.example.org"
]
}
]
In the case of s single TURN server, the `ice-servers.json` file should
look like this:
[
{
"urls": [
"turn:turn.example.org:443",
"turn:turn.example.org:443?transport=tcp"
],
"username": "galene",
"credential": "secret"
}
]
If you prefer to use coturn's `use-auth-secret` option, then your
`ice-servers.json` should look like this:
[
{
"Urls": [
"turn:turn.example.com:443",
"turn:turn.example.com:443?transport=tcp"
],
"username": "galene",
"credential": "secret",
"credentialType": "hmac-sha1"
}
]
For redundancy, you may set up multiple TURN servers, and ICE will use the
first one that works. If an `ice-servers.json` file is present and
Galène's built-in TURN server is enabled, then the external server will be
used in preference to the built-in server.
-- Juliusz Chroboczek <https://www.irif.fr/~jch/>
galene.go
View file @
5a7937b1
...
...
@@ -14,6 +14,7 @@ import (
"github.com/jech/galene/diskwriter"
"github.com/jech/galene/group"
"github.com/jech/galene/ice"
"github.com/jech/galene/turnserver"
"github.com/jech/galene/webserver"
)
...
...
@@ -42,6 +43,8 @@ func main() {
flag
.
BoolVar
(
&
group
.
UseMDNS
,
"mdns"
,
false
,
"gather mDNS addresses"
)
flag
.
BoolVar
(
&
ice
.
ICERelayOnly
,
"relay-only"
,
false
,
"require use of TURN relays for all media traffic"
)
flag
.
StringVar
(
&
turnserver
.
Address
,
"turn"
,
":1194"
,
"built-in TURN server address (
\"\"
to disable)"
)
flag
.
Parse
()
if
cpuprofile
!=
""
{
...
...
@@ -86,6 +89,12 @@ func main() {
go
group
.
ReadPublicGroups
()
err
:=
turnserver
.
Start
()
if
err
!=
nil
{
log
.
Printf
(
"TURN: %v"
,
err
)
}
defer
turnserver
.
Stop
()
serverDone
:=
make
(
chan
struct
{})
go
func
()
{
err
:=
webserver
.
Serve
(
httpAddr
,
dataDir
)
...
...
go.mod
View file @
5a7937b1
...
...
@@ -9,6 +9,7 @@ require (
github.com/pion/rtcp v1.2.6
github.com/pion/rtp v1.6.2
github.com/pion/sdp/v3 v3.0.4
github.com/pion/turn/v2 v2.0.5
github.com/pion/webrtc/v3 v3.0.3
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
)
ice/ice.go
View file @
5a7937b1
...
...
@@ -14,6 +14,8 @@ import (
"time"
"github.com/pion/webrtc/v3"
"github.com/jech/galene/turnserver"
)
type
Server
struct
{
...
...
@@ -101,6 +103,8 @@ func updateICEConfiguration() *configuration {
}
}
cf
.
ICEServers
=
append
(
cf
.
ICEServers
,
turnserver
.
ICEServers
()
...
)
if
ICERelayOnly
{
cf
.
ICETransportPolicy
=
webrtc
.
ICETransportPolicyRelay
}
...
...
turnserver/turnserver.go
0 → 100644
View file @
5a7937b1
package
turnserver
import
(
"crypto/rand"
"encoding/base64"
"errors"
"log"
"net"
"strconv"
"github.com/pion/turn/v2"
"github.com/pion/webrtc/v3"
)
var
username
string
var
password
string
var
server
*
turn
.
Server
var
Address
string
var
addresses
[]
net
.
Addr
func
publicAddresses
()
([]
net
.
IP
,
error
)
{
addrs
,
err
:=
net
.
InterfaceAddrs
()
if
err
!=
nil
{
return
nil
,
err
}
var
as
[]
net
.
IP
for
_
,
addr
:=
range
addrs
{
switch
addr
:=
addr
.
(
type
)
{
case
*
net
.
IPNet
:
a
:=
addr
.
IP
.
To4
()
if
a
==
nil
{
continue
}
if
!
a
.
IsGlobalUnicast
()
{
continue
}
if
a
[
0
]
==
10
||
a
[
0
]
==
172
&&
a
[
1
]
>=
16
&&
a
[
1
]
<
32
||
a
[
0
]
==
192
&&
a
[
1
]
==
168
{
continue
}
as
=
append
(
as
,
a
)
}
}
return
as
,
nil
}
func
listener
(
a
net
.
IP
,
port
int
,
relay
net
.
IP
)
(
*
turn
.
PacketConnConfig
,
*
turn
.
ListenerConfig
)
{
var
pcc
*
turn
.
PacketConnConfig
var
lc
*
turn
.
ListenerConfig
s
:=
net
.
JoinHostPort
(
a
.
String
(),
strconv
.
Itoa
(
port
))
p
,
err
:=
net
.
ListenPacket
(
"udp4"
,
s
)
if
err
==
nil
{
pcc
=
&
turn
.
PacketConnConfig
{
PacketConn
:
p
,
RelayAddressGenerator
:
&
turn
.
RelayAddressGeneratorStatic
{
RelayAddress
:
relay
,
Address
:
a
.
String
(),
},
}
}
else
{
log
.
Printf
(
"TURN: listenPacket(%v): %v"
,
s
,
err
)
}
l
,
err
:=
net
.
Listen
(
"tcp4"
,
s
)
if
err
==
nil
{
lc
=
&
turn
.
ListenerConfig
{
Listener
:
l
,
RelayAddressGenerator
:
&
turn
.
RelayAddressGeneratorStatic
{
RelayAddress
:
relay
,
Address
:
a
.
String
(),
},
}
}
else
{
log
.
Printf
(
"TURN: listen(%v): %v"
,
s
,
err
)
}
return
pcc
,
lc
}
func
Start
()
error
{
if
server
!=
nil
{
return
errors
.
New
(
"TURN server already started"
)
}
if
Address
==
""
{
return
errors
.
New
(
"built-in TURN server disabled"
)
}
addr
,
err
:=
net
.
ResolveUDPAddr
(
"udp4"
,
Address
)
if
err
!=
nil
{
return
err
}
username
=
"galene"
buf
:=
make
([]
byte
,
6
)
_
,
err
=
rand
.
Read
(
buf
)
if
err
!=
nil
{
return
err
}
buf2
:=
make
([]
byte
,
8
)
base64
.
RawStdEncoding
.
Encode
(
buf2
,
buf
)
password
=
string
(
buf2
)
var
lcs
[]
turn
.
ListenerConfig
var
pccs
[]
turn
.
PacketConnConfig
if
addr
.
IP
!=
nil
&&
!
addr
.
IP
.
IsUnspecified
()
{
a
:=
addr
.
IP
.
To4
()
if
a
==
nil
{
return
errors
.
New
(
"couldn't parse address"
)
}
pcc
,
lc
:=
listener
(
net
.
IP
{
0
,
0
,
0
,
0
},
addr
.
Port
,
a
)
if
pcc
!=
nil
{
pccs
=
append
(
pccs
,
*
pcc
)
addresses
=
append
(
addresses
,
&
net
.
UDPAddr
{
IP
:
a
,
Port
:
addr
.
Port
,
})
}
if
lc
!=
nil
{
lcs
=
append
(
lcs
,
*
lc
)
addresses
=
append
(
addresses
,
&
net
.
TCPAddr
{
IP
:
a
,
Port
:
addr
.
Port
,
})
}
}
else
{
as
,
err
:=
publicAddresses
()
if
err
!=
nil
{
return
err
}
if
len
(
as
)
==
0
{
return
errors
.
New
(
"no public addresses"
)
}
for
_
,
a
:=
range
as
{
pcc
,
lc
:=
listener
(
a
,
addr
.
Port
,
a
)
if
pcc
!=
nil
{
pccs
=
append
(
pccs
,
*
pcc
)
addresses
=
append
(
addresses
,
&
net
.
UDPAddr
{
IP
:
a
,
Port
:
addr
.
Port
,
})
}
if
lc
!=
nil
{
lcs
=
append
(
lcs
,
*
lc
)
addresses
=
append
(
addresses
,
&
net
.
TCPAddr
{
IP
:
a
,
Port
:
addr
.
Port
,
})
}
}
}
if
len
(
pccs
)
==
0
&&
len
(
lcs
)
==
0
{
return
errors
.
New
(
"couldn't establish any listeners"
)
}
server
,
err
=
turn
.
NewServer
(
turn
.
ServerConfig
{
Realm
:
"galene.org"
,
AuthHandler
:
func
(
u
,
r
string
,
src
net
.
Addr
)
([]
byte
,
bool
)
{
if
u
!=
username
||
r
!=
"galene.org"
{
return
nil
,
false
}
return
turn
.
GenerateAuthKey
(
u
,
r
,
password
),
true
},
ListenerConfigs
:
lcs
,
PacketConnConfigs
:
pccs
,
})
if
err
!=
nil
{
addresses
=
nil
return
err
}
return
nil
}
func
ICEServers
()
[]
webrtc
.
ICEServer
{
if
len
(
addresses
)
==
0
{
return
nil
}
var
urls
[]
string
for
_
,
a
:=
range
addresses
{
switch
a
:=
a
.
(
type
)
{
case
*
net
.
UDPAddr
:
urls
=
append
(
urls
,
"turn:"
+
a
.
String
())
case
*
net
.
TCPAddr
:
urls
=
append
(
urls
,
"turn:"
+
a
.
String
()
+
"?transport=tcp"
)
default
:
log
.
Printf
(
"unexpected TURN address %T"
,
a
)
}
}
return
[]
webrtc
.
ICEServer
{
{
URLs
:
urls
,
Username
:
username
,
Credential
:
password
,
},
}
}
func
Stop
()
{
addresses
=
nil
if
server
==
nil
{
return
}
server
.
Close
()
server
=
nil
return
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment