turn

package module
v0.6.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 21, 2018 License: BSD-3-Clause Imports: 15 Imported by: 0

README

Build Status Master status Build status GoDoc codecov Go Report stability-beta FOSSA Status

TURN

Package turn implements TURN [RFC5766] Traversal Using Relays around NAT. Complies to gortc principles as core package. Based on gortc/stun package. See gortcd for TURN server.

Example

If we have a TURN Server listening on example.com port 3478 (UDP) and know correct credentials, we can use it to relay data to peer which is listens on 10.0.0.1:34587 (UDP) and writing back any data it receives:

package main

import (
	"flag"
	"fmt"
	"net"
	"os"
	"time"

	"github.com/gortc/turn"
)

func main() {
	// Resolving to TURN server.
	raddr, err := net.ResolveUDPAddr("udp", "example.com:3478")
	if err != nil {
		panic(err)
	}
	c, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		panic(err)
	}
	client, clientErr := turn.NewClient(turn.ClientOptions{
		Conn:     c,
		// Credentials:
		Username: "user",
		Password: "secret",
	})
	if clientErr != nil {
		panic(clientErr)
	}
	a, allocErr := client.Allocate()
	if allocErr != nil {
		panic(allocErr)
	}
	peerAddr, resolveErr := net.ResolveUDPAddr("udp", "10.0.0.1:34587")
	if resolveErr != nil {
		panic(resolveErr)
	}
	permission, createErr := a.Create(peerAddr)
	if createErr != nil {
		panic(createErr)
	}
	// Permission implements net.Conn.
	if _, writeRrr := fmt.Fprint(permission, "hello world!"); writeRrr != nil {
		panic(peerAddr)
	}
	buf := make([]byte, 1500)
	n, readErr := permission.Read(buf)
	if readErr != nil {
		panic(readErr)
	}
	fmt.Println("got message:", string(buf[:n]))
	// Also you can use ChannelData messages to reduce overhead:
	if err := permission.Bind(); err != nil {
		panic(err)
	}
}
Server for experiments

You can use the turn.gortc.io:3478 gortcd TURN server instance for experiments. The only allowed peer address is 127.0.0.1:56780 (that is running near the gortcd) which will echo back any message it receives. Username is user, password is secret.

So just change example.com:3478 to turn.gortc.io:3478 and 10.0.0.1:34587 to 127.0.0.1:56780 in previous example and it should just work:

$ go get github.com/gortc/turn/cmd/turn-client
$ turn-client -server turn.gortc.io:3478 -peer 127.0.0.1:56780
0045	INFO	dial server	{"laddr": "192.168.88.10:36893", "raddr": "159.69.47.227:3478"}
0094	DEBUG	multiplexer	read	{"n": 104}
0095	DEBUG	multiplexer	got STUN data
0095	DEBUG	multiplexer	stun message	{"msg": "allocate error response l=84 attrs=5 id=PcPWfgQhiNnc7HR9"}
0144	DEBUG	multiplexer	read	{"n": 140}
0144	DEBUG	multiplexer	got STUN data
0144	DEBUG	multiplexer	stun message	{"msg": "allocate success response l=120 attrs=8 id=HNMg9zYhvO3D4wp8"}
0144	INFO	allocated
0192	DEBUG	multiplexer	read	{"n": 116}
0192	DEBUG	multiplexer	got STUN data
0192	DEBUG	multiplexer	stun message	{"msg": "create permission success response l=96 attrs=6 id=NVfoJXcKV8VaHpvK"}
0193	DEBUG	allocation.permission	using STUN to write
0242	DEBUG	multiplexer	read	{"n": 56}
0242	DEBUG	multiplexer	got STUN data
0242	DEBUG	multiplexer	stun message	{"msg": "data indication l=36 attrs=3 id=RoZvzIOY3/NG9GkT"}
0242	INFO	got message	{"body": "hello world!"}

Supported RFCs

  • RFC 5766 — Traversal Using Relays around NAT
    • UDP transport for client
    • TCP or TLS transport for client
  • RFC 6156 — TURN Extension for IPv6
  • RFC 7065 — TURN URI
  • RFC 5928 — TURN Resolution Mechanism #13
  • RFC 6062 — TURN Extension for TCP Allocations #14

Testing

Client behavior is tested and verified in many ways:

  • End-To-End with long-term credentials
    • coturn: The coturn server (linux)
    • gortcd: The gortcd server (windows)
  • Bunch of code static checkers (linters)
  • Unit-tests (linux {amd64, arm64}, windows}
  • Explicit API backward compatibility check, see api directory (relaxed until v1)

See TeamCity project and e2e directory for more information. Also the Wireshark .pcap files are available for some of e2e tests in artifacts for build.

Benchmarks

goos: linux
goarch: amd64
pkg: github.com/gortc/turn
PASS
benchmark                                 iter     time/iter     throughput   bytes alloc        allocs
---------                                 ----     ---------     ----------   -----------        ------
BenchmarkIsChannelData-12           2000000000    1.64 ns/op   6694.29 MB/s        0 B/op   0 allocs/op
BenchmarkChannelData_Encode-12       200000000    9.11 ns/op   1317.35 MB/s        0 B/op   0 allocs/op
BenchmarkChannelData_Decode-12       500000000    3.92 ns/op   3061.45 MB/s        0 B/op   0 allocs/op
BenchmarkChannelNumber/AddTo-12      100000000   12.60 ns/op                       0 B/op   0 allocs/op
BenchmarkChannelNumber/GetFrom-12    200000000    7.23 ns/op                       0 B/op   0 allocs/op
BenchmarkData/AddTo-12               100000000   18.80 ns/op                       0 B/op   0 allocs/op
BenchmarkData/AddToRaw-12            100000000   16.80 ns/op                       0 B/op   0 allocs/op
BenchmarkLifetime/AddTo-12           100000000   13.70 ns/op                       0 B/op   0 allocs/op
BenchmarkLifetime/GetFrom-12         200000000    7.10 ns/op                       0 B/op   0 allocs/op
ok  	github.com/gortc/turn	19.110s

Documentation

Overview

Package turn implements RFC 5766 Traversal Using Relays around NAT.

Index

Examples

Constants

View Source
const (
	// DefaultPort for TURN is same as STUN.
	DefaultPort = stun.DefaultPort
	// DefaultTLSPort is for TURN over TLS and is same as STUN.
	DefaultTLSPort = stun.DefaultTLSPort
)

Default ports for TURN from RFC 5766 Section 4.

View Source
const (
	Scheme       = "turn"
	SchemeSecure = "turns"
)

Scheme definitions from RFC 7065 Section 3.2.

View Source
const (
	TransportTCP = "tcp"
	TransportUDP = "udp"
)

Transport definitions as in RFC 7065.

View Source
const DefaultLifetime = time.Minute * 10

DefaultLifetime in RFC 5766 is 10 minutes.

RFC 5766 Section 2.2

Variables

View Source
var (
	// ErrAlreadyBound means that selected permission already has bound channel number.
	ErrAlreadyBound = errors.New("channel already bound")
	// ErrNotBound means that selected permission already has no channel number.
	ErrNotBound = errors.New("channel is not bound")
)
View Source
var (
	// AllocateRequest is shorthand for allocation request message type.
	AllocateRequest = stun.NewType(stun.MethodAllocate, stun.ClassRequest)
	// CreatePermissionRequest is shorthand for create permission request type.
	CreatePermissionRequest = stun.NewType(stun.MethodCreatePermission, stun.ClassRequest)
	// SendIndication is shorthand for send indication message type.
	SendIndication = stun.NewType(stun.MethodSend, stun.ClassIndication)
	// RefreshRequest is shorthand for refresh request message type.
	RefreshRequest = stun.NewType(stun.MethodRefresh, stun.ClassRequest)
)
View Source
var ErrBadChannelDataLength = errors.New("channelData length != len(Data)")

ErrBadChannelDataLength means that channel data length is not equal to actual data length.

View Source
var ErrInvalidChannelNumber = errors.New("channel number not in [0x4000, 0x7FFF]")

ErrInvalidChannelNumber means that channel number is not valid as by RFC 5766 Section 11.

View Source
var ErrNotImplemented = errors.New("functionality not implemented")

ErrNotImplemented means that functionality is not currently implemented, but it will be (eventually).

View Source
var RequestedTransportUDP stun.Setter = RequestedTransport{
	Protocol: ProtoUDP,
}

RequestedTransportUDP is setter for requested transport attribute with value ProtoUDP (17).

View Source
var ZeroLifetime stun.Setter = Lifetime{}

ZeroLifetime is shorthand for setting zero lifetime that indicates to close allocation.

Functions

func IsChannelData added in v0.2.1

func IsChannelData(buf []byte) bool

IsChannelData returns true if buf looks like the ChannelData Message.

func ZapChannelNumber added in v0.4.6

func ZapChannelNumber(key string, v ChannelNumber) zap.Field

ZapChannelNumber returns zap.Field for ChannelNumber.

Types

type Addr added in v0.4.0

type Addr struct {
	IP   net.IP
	Port int
}

Addr is ip:port.

func (Addr) Equal added in v0.4.0

func (a Addr) Equal(b Addr) bool

Equal returns true if b == a.

func (*Addr) FromUDPAddr added in v0.4.0

func (a *Addr) FromUDPAddr(n *net.UDPAddr)

FromUDPAddr sets addr to UDPAddr.

func (Addr) Network added in v0.4.0

func (Addr) Network() string

Network implements net.Addr.

func (Addr) String added in v0.4.0

func (a Addr) String() string

type Allocation added in v0.4.0

type Allocation struct {
	// contains filtered or unexported fields
}

Allocation reflects TURN Allocation.

func (*Allocation) Create added in v0.4.1

func (a *Allocation) Create(peer net.Addr) (*Permission, error)

Create creates new permission to peer.

func (*Allocation) CreateUDP added in v0.4.0

func (a *Allocation) CreateUDP(addr *net.UDPAddr) (*Permission, error)

CreateUDP creates new UDP Permission to peer with provided addr.

type ChannelData added in v0.2.1

type ChannelData struct {
	Data    []byte // can be subslice of Raw
	Length  int    // ignored while encoding, len(Data) is used
	Padding bool   // use  padding
	Number  ChannelNumber
	Raw     []byte
}

ChannelData represents The ChannelData Message.

See RFC 5766 Section 11.4

func (*ChannelData) Decode added in v0.2.1

func (c *ChannelData) Decode() error

Decode decodes The ChannelData Message from Raw.

func (*ChannelData) Encode added in v0.2.1

func (c *ChannelData) Encode()

Encode encodes ChannelData Message to Raw.

func (*ChannelData) Equal added in v0.2.1

func (c *ChannelData) Equal(b *ChannelData) bool

Equal returns true if b == c.

func (*ChannelData) Reset added in v0.2.1

func (c *ChannelData) Reset()

Reset resets Length, Data and Raw length.

func (*ChannelData) WriteHeader added in v0.2.1

func (c *ChannelData) WriteHeader()

WriteHeader writes channel number and length.

type ChannelNumber

type ChannelNumber int // encoded as uint16

ChannelNumber represents CHANNEL-NUMBER attribute.

The CHANNEL-NUMBER attribute contains the number of the channel.

RFC 5766 Section 14.1

func (ChannelNumber) AddTo

func (n ChannelNumber) AddTo(m *stun.Message) error

AddTo adds CHANNEL-NUMBER to message.

func (*ChannelNumber) GetFrom

func (n *ChannelNumber) GetFrom(m *stun.Message) error

GetFrom decodes CHANNEL-NUMBER from message.

func (ChannelNumber) String

func (n ChannelNumber) String() string

func (ChannelNumber) Valid added in v0.2.3

func (n ChannelNumber) Valid() bool

Valid returns true if channel number has correct value that complies RFC 5766 Section 11 range.

type Client added in v0.4.0

type Client struct {
	// contains filtered or unexported fields
}

Client for TURN server.

Provides transparent net.Conn interfaces to remote peers.

func NewClient added in v0.4.0

func NewClient(o ClientOptions) (*Client, error)

NewClient creates and initializes new TURN client.

func (*Client) Allocate added in v0.4.0

func (c *Client) Allocate() (*Allocation, error)

Allocate creates an allocation for current 5-tuple. Currently there can be only one allocation per client, because client wraps one net.Conn.

func (*Client) RefreshRate added in v0.6.2

func (c *Client) RefreshRate() time.Duration

RefreshRate returns current rate of refresh requests.

type ClientOptions added in v0.4.0

type ClientOptions struct {
	Conn net.Conn
	STUN STUNClient  // optional STUN client
	Log  *zap.Logger // defaults to Nop

	// Long-term integrity.
	Username string
	Password string

	// STUN client options.
	RTO          time.Duration
	NoRetransmit bool

	// TURN options.
	RefreshRate     time.Duration
	RefreshDisabled bool
}

ClientOptions contains available config for TURN client.

type Data

type Data []byte

Data represents DATA attribute.

The DATA attribute is present in all Send and Data indications. The value portion of this attribute is variable length and consists of the application data (that is, the data that would immediately follow the UDP header if the data was been sent directly between the client and the peer).

RFC 5766 Section 14.4

func (Data) AddTo

func (d Data) AddTo(m *stun.Message) error

AddTo adds DATA to message.

func (*Data) GetFrom

func (d *Data) GetFrom(m *stun.Message) error

GetFrom decodes DATA from message.

type DontFragmentAttr

type DontFragmentAttr struct{}

DontFragmentAttr represents DONT-FRAGMENT attribute.

var DontFragment DontFragmentAttr

DontFragment is shorthand for DontFragmentAttr.

func (DontFragmentAttr) AddTo

func (DontFragmentAttr) AddTo(m *stun.Message) error

AddTo adds DONT-FRAGMENT attribute to message.

func (DontFragmentAttr) IsSet

func (DontFragmentAttr) IsSet(m *stun.Message) bool

IsSet returns true if DONT-FRAGMENT attribute is set.

type EvenPort

type EvenPort struct {
	// ReservePort means that the server is requested to reserve
	// the next-higher port number (on the same IP address)
	// for a subsequent allocation.
	ReservePort bool
}

EvenPort represents EVEN-PORT attribute.

This attribute allows the client to request that the port in the relayed transport address be even, and (optionally) that the server reserve the next-higher port number.

RFC 5766 Section 14.6

func (EvenPort) AddTo

func (p EvenPort) AddTo(m *stun.Message) error

AddTo adds EVEN-PORT to message.

func (*EvenPort) GetFrom

func (p *EvenPort) GetFrom(m *stun.Message) error

GetFrom decodes EVEN-PORT from message.

func (EvenPort) String

func (p EvenPort) String() string

type FiveTuple added in v0.4.0

type FiveTuple struct {
	Client Addr
	Server Addr
	Proto  Protocol
}

FiveTuple represents 5-TUPLE value.

func (FiveTuple) Equal added in v0.4.0

func (t FiveTuple) Equal(b FiveTuple) bool

Equal returns true if b == t.

func (FiveTuple) String added in v0.4.0

func (t FiveTuple) String() string

type Lifetime

type Lifetime struct {
	time.Duration
}

Lifetime represents LIFETIME attribute.

The LIFETIME attribute represents the duration for which the server will maintain an allocation in the absence of a refresh. The value portion of this attribute is 4-bytes long and consists of a 32-bit unsigned integral value representing the number of seconds remaining until expiration.

RFC 5766 Section 14.2

Example
// Encoding lifetime to message.
m := new(stun.Message)
Lifetime{time.Minute}.AddTo(m)
m.WriteHeader()

// Decoding message.
mDec := new(stun.Message)
if _, err := m.WriteTo(mDec); err != nil {
	panic(err)
}
// Decoding lifetime from message.
l := Lifetime{}
l.GetFrom(m)
fmt.Println("Decoded:", l)
Output:

Decoded: 1m0s

func (Lifetime) AddTo

func (l Lifetime) AddTo(m *stun.Message) error

AddTo adds LIFETIME to message.

func (*Lifetime) GetFrom

func (l *Lifetime) GetFrom(m *stun.Message) error

GetFrom decodes LIFETIME from message.

type PeerAddress

type PeerAddress struct {
	IP   net.IP
	Port int
}

PeerAddress implements XOR-PEER-ADDRESS attribute.

The XOR-PEER-ADDRESS specifies the address and port of the peer as seen from the TURN server. (For example, the peer's server-reflexive transport address if the peer is behind a NAT.)

RFC 5766 Section 14.3

func (PeerAddress) AddTo

func (a PeerAddress) AddTo(m *stun.Message) error

AddTo adds XOR-PEER-ADDRESS to message.

func (*PeerAddress) GetFrom

func (a *PeerAddress) GetFrom(m *stun.Message) error

GetFrom decodes XOR-PEER-ADDRESS from message.

func (PeerAddress) String

func (a PeerAddress) String() string

type Permission added in v0.4.0

type Permission struct {
	// contains filtered or unexported fields
}

Permission implements net.PacketConn.

func (*Permission) Bind added in v0.4.0

func (p *Permission) Bind() error

Bind performs binding transaction, allocating channel binding for the permission.

func (*Permission) Binding added in v0.4.0

func (p *Permission) Binding() ChannelNumber

Binding returns current channel number or 0 if not bound.

func (*Permission) Bound added in v0.4.0

func (p *Permission) Bound() bool

Bound returns true if channel number is bound for current permission.

func (*Permission) Close added in v0.4.0

func (p *Permission) Close() error

Close stops all refreshing loops for permission and removes it from allocation.

func (*Permission) LocalAddr added in v0.4.0

func (p *Permission) LocalAddr() net.Addr

LocalAddr is relayed address from TURN server.

func (*Permission) Read added in v0.4.0

func (p *Permission) Read(b []byte) (n int, err error)

Read data from peer.

func (*Permission) RemoteAddr added in v0.4.0

func (p *Permission) RemoteAddr() net.Addr

RemoteAddr is peer address.

func (*Permission) SetDeadline added in v0.4.0

func (p *Permission) SetDeadline(t time.Time) error

SetDeadline implements net.Conn.

func (*Permission) SetReadDeadline added in v0.4.0

func (p *Permission) SetReadDeadline(t time.Time) error

SetReadDeadline implements net.Conn.

func (*Permission) SetWriteDeadline added in v0.4.0

func (p *Permission) SetWriteDeadline(t time.Time) error

SetWriteDeadline implements net.Conn.

func (*Permission) Write added in v0.4.0

func (p *Permission) Write(b []byte) (n int, err error)

Write sends buffer to peer.

If permission is bound, the ChannelData message will be used.

type Protocol

type Protocol byte

Protocol is IANA assigned protocol number.

const (
	// ProtoUDP is IANA assigned protocol number for UDP.
	ProtoUDP Protocol = 17
)

func (Protocol) String

func (p Protocol) String() string

type RelayedAddress

type RelayedAddress struct {
	IP   net.IP
	Port int
}

RelayedAddress implements XOR-RELAYED-ADDRESS attribute.

The XOR-PEER-ADDRESS specifies the address and port of the peer as seen from the TURN server. (For example, the peer's server-reflexive transport address if the peer is behind a NAT.)

RFC 5766 Section 14.5

func (RelayedAddress) AddTo

func (a RelayedAddress) AddTo(m *stun.Message) error

AddTo adds XOR-PEER-ADDRESS to message.

func (*RelayedAddress) GetFrom

func (a *RelayedAddress) GetFrom(m *stun.Message) error

GetFrom decodes XOR-PEER-ADDRESS from message.

func (RelayedAddress) String

func (a RelayedAddress) String() string

type RequestedAddressFamily added in v0.5.3

type RequestedAddressFamily byte

RequestedAddressFamily represents the REQUESTED-ADDRESS-FAMILY Attribute as defined in RFC 6156 Section 4.1.1.

const (
	RequestedFamilyIPv4 RequestedAddressFamily = 0x01
	RequestedFamilyIPv6 RequestedAddressFamily = 0x02
)

Values for RequestedAddressFamily as defined in RFC 6156 Section 4.1.1.

func (RequestedAddressFamily) AddTo added in v0.5.3

AddTo adds REQUESTED-ADDRESS-FAMILY to message.

func (*RequestedAddressFamily) GetFrom added in v0.5.3

func (f *RequestedAddressFamily) GetFrom(m *stun.Message) error

GetFrom decodes REQUESTED-ADDRESS-FAMILY from message.

func (RequestedAddressFamily) String added in v0.5.3

func (f RequestedAddressFamily) String() string

type RequestedTransport

type RequestedTransport struct {
	Protocol Protocol
}

RequestedTransport represents REQUESTED-TRANSPORT attribute.

This attribute is used by the client to request a specific transport protocol for the allocated transport address. RFC 5766 only allows the use of codepoint 17 (User Datagram Protocol).

RFC 5766 Section 14.7

func (RequestedTransport) AddTo

func (t RequestedTransport) AddTo(m *stun.Message) error

AddTo adds REQUESTED-TRANSPORT to message.

func (*RequestedTransport) GetFrom

func (t *RequestedTransport) GetFrom(m *stun.Message) error

GetFrom decodes REQUESTED-TRANSPORT from message.

func (RequestedTransport) String

func (t RequestedTransport) String() string

type ReservationToken

type ReservationToken []byte

ReservationToken represents RESERVATION-TOKEN attribute.

The RESERVATION-TOKEN attribute contains a token that uniquely identifies a relayed transport address being held in reserve by the server. The server includes this attribute in a success response to tell the client about the token, and the client includes this attribute in a subsequent Allocate request to request the server use that relayed transport address for the allocation.

RFC 5766 Section 14.9

func (ReservationToken) AddTo

func (t ReservationToken) AddTo(m *stun.Message) error

AddTo adds RESERVATION-TOKEN to message.

func (*ReservationToken) GetFrom

func (t *ReservationToken) GetFrom(m *stun.Message) error

GetFrom decodes RESERVATION-TOKEN from message.

type STUNClient added in v0.4.0

type STUNClient interface {
	Indicate(m *stun.Message) error
	Do(m *stun.Message, f func(e stun.Event)) error
}

STUNClient abstracts STUN protocol interaction.

type URI added in v0.5.2

type URI struct {
	Scheme    string
	Host      string
	Port      int
	Transport string
}

URI as defined in RFC 7065.

func ParseURI added in v0.5.2

func ParseURI(rawURI string) (URI, error)

ParseURI parses URI from string.

func (URI) String added in v0.5.2

func (u URI) String() string

Directories

Path Synopsis
cmd
e2e
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL