mirror of
https://github.com/jech/galene.git
synced 2024-11-14 12:45:58 +01:00
c103d1cfb0
The default configuration is now defined by an explicit value "auto", which is easier to check and to explain.
251 lines
4.4 KiB
Go
251 lines
4.4 KiB
Go
package turnserver
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"log"
|
|
"net"
|
|
"strconv"
|
|
"sync"
|
|
|
|
"github.com/pion/turn/v2"
|
|
"github.com/pion/webrtc/v3"
|
|
)
|
|
|
|
var username string
|
|
var password string
|
|
var Address string
|
|
|
|
var mu sync.Mutex
|
|
var addresses []net.Addr
|
|
var server *turn.Server
|
|
|
|
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 {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
if server != nil {
|
|
return nil
|
|
}
|
|
|
|
if Address == "" {
|
|
return errors.New("built-in TURN server disabled")
|
|
}
|
|
|
|
ad := Address
|
|
if Address == "auto" {
|
|
ad = ":1194"
|
|
}
|
|
addr, err := net.ResolveUDPAddr("udp4", ad)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("Starting built-in TURN server")
|
|
|
|
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 {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
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() error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
addresses = nil
|
|
if server == nil {
|
|
return nil
|
|
}
|
|
log.Printf("Stopping built-in TURN server")
|
|
err := server.Close()
|
|
server = nil
|
|
return err
|
|
}
|
|
|
|
func StartStop(start bool) error {
|
|
if Address == "auto" {
|
|
if start {
|
|
return Start()
|
|
}
|
|
return Stop()
|
|
} else if Address == "" {
|
|
return Stop()
|
|
}
|
|
return Start()
|
|
}
|