Packages
stun
1.2.22
1.2.22
1.2.21
1.2.20
1.2.19
1.2.18
1.2.17
1.2.16
1.2.15
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.0
1.0.47
1.0.46
1.0.45
1.0.44
1.0.43
1.0.42
1.0.41
1.0.40
1.0.38
1.0.37
1.0.36
1.0.34
1.0.33
1.0.32
1.0.31
1.0.30
1.0.29
1.0.28
1.0.27
1.0.26
1.0.25
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.17
1.0.15
1.0.14
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-beta1
STUN and TURN library for Erlang / Elixir
Current section
Files
Jump to
Current section
Files
README.md
# STUN
[](https://github.com/processone/stun/actions/workflows/ci.yml)
[](https://coveralls.io/github/processone/stun?branch=master)
[](https://hex.pm/packages/stun)
STUN and TURN library for Erlang / Elixir.
Both [STUN](https://en.wikipedia.org/wiki/STUN) (Session Traversal
Utilities for NAT) and
[TURN](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT)
standards are used as technics to establish media connection between
peers for VoIP (for example using
[SIP](https://en.wikipedia.org/wiki/Session_Initiation_Protocol) or
[Jingle](http://xmpp.org/about-xmpp/technology-overview/jingle/)) and
[WebRTC](https://en.wikipedia.org/wiki/WebRTC).
They are part of a more general negotiation technique know as
[ICE](https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment)
(Interactive Connectivity Establishment).
To summarize:
* A STUN server is used to get an external network address. It does
not serve as a relay for the media traffic.
* TURN servers are used to relay traffic if direct (peer to peer)
connection fails.
## Build
This is a pure Erlang implementation, so you do not need to have
specific C libraries installed for the STUN, TURN, ICE code.
However, this code depends on ProcessOne
[Fast TLS](https://github.com/processone/fast_tls), which depends on
OpenSSL 1.0.0+ library.
### Generic build
You can trigger build with:
make
# Usage
The following sequence describe a STUN establishment.
First, start the application and stun listener at 127.0.0.1:
```
1> application:start(stun).
ok
2> stun_listener:add_listener({127, 0, 0, 1}, 3478, udp, []).
ok
```
Then, you can form and send a BindRequest:
```
3> rr(stun).
[state,stun,turn]
4> random:seed(erlang:timestamp()).
undefined
```
You can form a transaction id. Should be always 96 bit:
```
5> TrID = random:uniform(1 bsl 96).
41809861624941132369239212033
```
You then create a BindRequest message.
`16#001` is `?STUN_METHOD_BINDING`, defined in `include/stun.hrl`
```
6> Msg = #stun{method = 16#001, class = request, trid = TrID}.
#stun{class = request,method = 1,magic = 554869826,
trid = 41809861624941132369239212033,raw = <<>>,
unsupported = [],'ALTERNATE-SERVER' = undefined,
'CHANNEL-NUMBER' = undefined,'DATA' = undefined,
'DONT-FRAGMENT' = false,'ERROR-CODE' = undefined,
'LIFETIME' = undefined,'MAPPED-ADDRESS' = undefined,
'MESSAGE-INTEGRITY' = undefined,'NONCE' = undefined,
'REALM' = undefined,'REQUESTED-TRANSPORT' = undefined,
'SOFTWARE' = undefined,'UNKNOWN-ATTRIBUTES' = [],
'USERNAME' = undefined,'XOR-MAPPED-ADDRESS' = undefined,
'XOR-PEER-ADDRESS' = [],'XOR-RELAYED-ADDRESS' = undefined}
```
You can then establish connection to running server:
```
7> {ok, Socket} = gen_udp:open(0, [binary, {ip,
7> {127,0,0,1}},{active,false}]).
{ok,#Port<0.1020>}
8> {ok, Addr} = inet:sockname(Socket).
{ok,{{127,0,0,1},41906}}
```
The following call is for encoding BindRequest:
```
9> PktOut = stun_codec:encode(Msg).
<<0,1,0,0,33,18,164,66,135,24,78,148,65,4,128,0,0,0,0,1>>
```
The BindRequest can then be send:
```
10> gen_udp:send(Socket, {127,0,0,1}, 3478, PktOut).
ok
```
The follow code receives the BindResponse:
```
11> {ok, {_, _, PktIn}} = gen_udp:recv(Socket, 0).
{ok,{{127,0,0,1},
3478,
<<1,1,0,32,33,18,164,66,135,24,78,148,65,4,128,0,0,0,0,
1,128,34,0,15,...>>}}
```
You can then decode the BindResponse:
```
12> {ok, Response} = stun_codec:decode(PktIn, datagram).
{ok,#stun{class = response,method = 1,magic = 554869826,
trid = 41809861624941132369239212033,raw = <<>>,
unsupported = [],'ALTERNATE-SERVER' = undefined,
'CHANNEL-NUMBER' = undefined,'DATA' = undefined,
'DONT-FRAGMENT' = false,'ERROR-CODE' = undefined,
'LIFETIME' = undefined,'MAPPED-ADDRESS' = undefined,
'MESSAGE-INTEGRITY' = undefined,'NONCE' = undefined,
'REALM' = undefined,'REQUESTED-TRANSPORT' = undefined,
'SOFTWARE' = <<"P1 STUN library">>,
'UNKNOWN-ATTRIBUTES' = [],'USERNAME' = undefined,
'XOR-MAPPED-ADDRESS' = {{127,0,0,1},41906},
'XOR-PEER-ADDRESS' = [],'XOR-RELAYED-ADDRESS' = undefined}}
```
Finally, checking 'XOR-MAPPED-ADDRESS' attribute, should be equal to locally
binded address:
```
13> Addr == Response#stun.'XOR-MAPPED-ADDRESS'.
true
```
## Development
### Test
#### Unit test
You can run eunit test with the command:
make test
# References
You can refer to IETF specifications to learn more:
* [RFC 5389](https://tools.ietf.org/html/rfc5389): Session Traversal
Utilities for NAT (STUN).
* [RFC 5766](https://tools.ietf.org/html/rfc5766): Traversal Using
Relays around NAT (TURN): Relay Extensions to STUN.
* [RFC 5245](https://tools.ietf.org/html/rfc5245): Interactive
Connectivity Establishment (ICE): A Protocol for NAT Traversal for
Offer/Answer Protocols.
* [RFC 6544](https://tools.ietf.org/html/rfc6544): TCP Candidates with
Interactive Connectivity Establishment (ICE)
## EDoc documentation
You can check this library's
[EDoc documentation](edoc.html),
generated automatically from the source code comments.