+65
@@ -0,0 +1,65 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Addr is ip:port.
|
||||
type Addr struct {
|
||||
IP net.IP
|
||||
Port int
|
||||
}
|
||||
|
||||
// Network implements net.Addr.
|
||||
func (Addr) Network() string { return "turn" }
|
||||
|
||||
// FromUDPAddr sets addr to UDPAddr.
|
||||
func (a *Addr) FromUDPAddr(n *net.UDPAddr) {
|
||||
a.IP = n.IP
|
||||
a.Port = n.Port
|
||||
}
|
||||
|
||||
// Equal returns true if b == a.
|
||||
func (a Addr) Equal(b Addr) bool {
|
||||
if a.Port != b.Port {
|
||||
return false
|
||||
}
|
||||
return a.IP.Equal(b.IP)
|
||||
}
|
||||
|
||||
// EqualIP returns true if a and b have equal IP addresses.
|
||||
func (a Addr) EqualIP(b Addr) bool {
|
||||
return a.IP.Equal(b.IP)
|
||||
}
|
||||
|
||||
func (a Addr) String() string {
|
||||
return fmt.Sprintf("%s:%d", a.IP, a.Port)
|
||||
}
|
||||
|
||||
// FiveTuple represents 5-TUPLE value.
|
||||
type FiveTuple struct {
|
||||
Client Addr
|
||||
Server Addr
|
||||
Proto Protocol
|
||||
}
|
||||
|
||||
func (t FiveTuple) String() string {
|
||||
return fmt.Sprintf("%s->%s (%s)",
|
||||
t.Client, t.Server, t.Proto,
|
||||
)
|
||||
}
|
||||
|
||||
// Equal returns true if b == t.
|
||||
func (t FiveTuple) Equal(b FiveTuple) bool {
|
||||
if t.Proto != b.Proto {
|
||||
return false
|
||||
}
|
||||
if !t.Client.Equal(b.Client) {
|
||||
return false
|
||||
}
|
||||
if !t.Server.Equal(b.Server) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ChannelData represents The ChannelData Message.
|
||||
//
|
||||
// See RFC 5766 Section 11.4
|
||||
type ChannelData struct {
|
||||
Data []byte // can be subslice of Raw
|
||||
Length int // ignored while encoding, len(Data) is used
|
||||
Number ChannelNumber
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
// Equal returns true if b == c.
|
||||
func (c *ChannelData) Equal(b *ChannelData) bool {
|
||||
if c == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
if c == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
if c.Number != b.Number {
|
||||
return false
|
||||
}
|
||||
if len(c.Data) != len(b.Data) {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(c.Data, b.Data)
|
||||
}
|
||||
|
||||
// grow ensures that internal buffer will fit v more bytes and
|
||||
// increases it capacity if necessary.
|
||||
//
|
||||
// Similar to stun.Message.grow method.
|
||||
func (c *ChannelData) grow(v int) {
|
||||
n := len(c.Raw) + v
|
||||
for cap(c.Raw) < n {
|
||||
c.Raw = append(c.Raw, 0)
|
||||
}
|
||||
c.Raw = c.Raw[:n]
|
||||
}
|
||||
|
||||
// Reset resets Length, Data and Raw length.
|
||||
func (c *ChannelData) Reset() {
|
||||
c.Raw = c.Raw[:0]
|
||||
c.Length = 0
|
||||
c.Data = c.Data[:0]
|
||||
}
|
||||
|
||||
// Encode encodes ChannelData Message to Raw.
|
||||
func (c *ChannelData) Encode() {
|
||||
c.Raw = c.Raw[:0]
|
||||
c.WriteHeader()
|
||||
c.Raw = append(c.Raw, c.Data...)
|
||||
padded := nearestPaddedValueLength(len(c.Raw))
|
||||
if bytesToAdd := padded - len(c.Raw); bytesToAdd > 0 {
|
||||
for i := 0; i < bytesToAdd; i++ {
|
||||
c.Raw = append(c.Raw, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const padding = 4
|
||||
|
||||
func nearestPaddedValueLength(l int) int {
|
||||
n := padding * (l / padding)
|
||||
if n < l {
|
||||
n += padding
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// WriteHeader writes channel number and length.
|
||||
func (c *ChannelData) WriteHeader() {
|
||||
if len(c.Raw) < channelDataHeaderSize {
|
||||
// Making WriteHeader call valid even when c.Raw
|
||||
// is nil or len(c.Raw) is less than needed for header.
|
||||
c.grow(channelDataHeaderSize)
|
||||
}
|
||||
// Early bounds check to guarantee safety of writes below.
|
||||
_ = c.Raw[:channelDataHeaderSize]
|
||||
binary.BigEndian.PutUint16(c.Raw[:channelDataNumberSize], uint16(c.Number))
|
||||
binary.BigEndian.PutUint16(c.Raw[channelDataNumberSize:channelDataHeaderSize],
|
||||
uint16(len(c.Data)),
|
||||
)
|
||||
}
|
||||
|
||||
// ErrBadChannelDataLength means that channel data length is not equal
|
||||
// to actual data length.
|
||||
var ErrBadChannelDataLength = errors.New("channelData length != len(Data)")
|
||||
|
||||
// Decode decodes The ChannelData Message from Raw.
|
||||
func (c *ChannelData) Decode() error {
|
||||
buf := c.Raw
|
||||
if len(buf) < channelDataHeaderSize {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
num := binary.BigEndian.Uint16(buf[:channelDataNumberSize])
|
||||
c.Number = ChannelNumber(num)
|
||||
l := binary.BigEndian.Uint16(buf[channelDataNumberSize:channelDataHeaderSize])
|
||||
c.Data = buf[channelDataHeaderSize:]
|
||||
c.Length = int(l)
|
||||
if !c.Number.Valid() {
|
||||
return ErrInvalidChannelNumber
|
||||
}
|
||||
if int(l) < len(c.Data) {
|
||||
c.Data = c.Data[:int(l)]
|
||||
}
|
||||
if int(l) > len(buf[channelDataHeaderSize:]) {
|
||||
return ErrBadChannelDataLength
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
channelDataLengthSize = 2
|
||||
channelDataNumberSize = channelDataLengthSize
|
||||
channelDataHeaderSize = channelDataLengthSize + channelDataNumberSize
|
||||
)
|
||||
|
||||
// IsChannelData returns true if buf looks like the ChannelData Message.
|
||||
func IsChannelData(buf []byte) bool {
|
||||
if len(buf) < channelDataHeaderSize {
|
||||
return false
|
||||
}
|
||||
|
||||
if int(binary.BigEndian.Uint16(buf[channelDataNumberSize:channelDataHeaderSize])) > len(buf[channelDataHeaderSize:]) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Quick check for channel number.
|
||||
num := binary.BigEndian.Uint16(buf[0:channelNumberSize])
|
||||
return isChannelNumberValid(num)
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// ChannelNumber represents CHANNEL-NUMBER attribute.
|
||||
//
|
||||
// The CHANNEL-NUMBER attribute contains the number of the channel.
|
||||
//
|
||||
// RFC 5766 Section 14.1
|
||||
type ChannelNumber uint16 // encoded as uint16
|
||||
|
||||
func (n ChannelNumber) String() string { return strconv.Itoa(int(n)) }
|
||||
|
||||
// 16 bits of uint + 16 bits of RFFU = 0.
|
||||
const channelNumberSize = 4
|
||||
|
||||
// AddTo adds CHANNEL-NUMBER to message.
|
||||
func (n ChannelNumber) AddTo(m *stun.Message) error {
|
||||
v := make([]byte, channelNumberSize)
|
||||
binary.BigEndian.PutUint16(v[:2], uint16(n))
|
||||
// v[2:4] are zeroes (RFFU = 0)
|
||||
m.Add(stun.AttrChannelNumber, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFrom decodes CHANNEL-NUMBER from message.
|
||||
func (n *ChannelNumber) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrChannelNumber)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stun.CheckSize(stun.AttrChannelNumber, len(v), channelNumberSize); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v[channelNumberSize-1] // asserting length
|
||||
*n = ChannelNumber(binary.BigEndian.Uint16(v[:2]))
|
||||
// v[2:4] is RFFU and equals to 0.
|
||||
return nil
|
||||
}
|
||||
|
||||
// See https://tools.ietf.org/html/rfc5766#section-11:
|
||||
//
|
||||
// 0x4000 through 0x7FFF: These values are the allowed channel
|
||||
// numbers (16,383 possible values).
|
||||
const (
|
||||
MinChannelNumber = 0x4000
|
||||
MaxChannelNumber = 0x7FFF
|
||||
)
|
||||
|
||||
// ErrInvalidChannelNumber means that channel number is not valid as by RFC 5766 Section 11.
|
||||
var ErrInvalidChannelNumber = errors.New("channel number not in [0x4000, 0x7FFF]")
|
||||
|
||||
// isChannelNumberValid returns true if c in [0x4000, 0x7FFF].
|
||||
func isChannelNumberValid(c uint16) bool {
|
||||
return c >= MinChannelNumber && c <= MaxChannelNumber
|
||||
}
|
||||
|
||||
// Valid returns true if channel number has correct value that complies RFC 5766 Section 11 range.
|
||||
func (n ChannelNumber) Valid() bool {
|
||||
return isChannelNumberValid(uint16(n))
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package proto
|
||||
|
||||
import "github.com/pion/stun"
|
||||
|
||||
// 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
|
||||
type Data []byte
|
||||
|
||||
// AddTo adds DATA to message.
|
||||
func (d Data) AddTo(m *stun.Message) error {
|
||||
m.Add(stun.AttrData, d)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFrom decodes DATA from message.
|
||||
func (d *Data) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = v
|
||||
return nil
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package proto
|
||||
|
||||
import "github.com/pion/stun"
|
||||
|
||||
// DontFragmentAttr represents DONT-FRAGMENT attribute.
|
||||
type DontFragmentAttr struct{}
|
||||
|
||||
// AddTo adds DONT-FRAGMENT attribute to message.
|
||||
func (DontFragmentAttr) AddTo(m *stun.Message) error {
|
||||
m.Add(stun.AttrDontFragment, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsSet returns true if DONT-FRAGMENT attribute is set.
|
||||
func (DontFragmentAttr) IsSet(m *stun.Message) bool {
|
||||
_, err := m.Get(stun.AttrDontFragment)
|
||||
return err == nil
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package proto
|
||||
|
||||
import "github.com/pion/stun"
|
||||
|
||||
// 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
|
||||
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
|
||||
}
|
||||
|
||||
func (p EvenPort) String() string {
|
||||
if p.ReservePort {
|
||||
return "reserve: true"
|
||||
}
|
||||
return "reserve: false"
|
||||
}
|
||||
|
||||
const (
|
||||
evenPortSize = 1
|
||||
firstBitSet = (1 << 8) - 1 // 0b100000000
|
||||
)
|
||||
|
||||
// AddTo adds EVEN-PORT to message.
|
||||
func (p EvenPort) AddTo(m *stun.Message) error {
|
||||
v := make([]byte, evenPortSize)
|
||||
if p.ReservePort {
|
||||
// Set first bit to 1.
|
||||
v[0] = firstBitSet
|
||||
}
|
||||
m.Add(stun.AttrEvenPort, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFrom decodes EVEN-PORT from message.
|
||||
func (p *EvenPort) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrEvenPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stun.CheckSize(stun.AttrEvenPort, len(v), evenPortSize); err != nil {
|
||||
return err
|
||||
}
|
||||
if v[0]&firstBitSet > 0 {
|
||||
p.ReservePort = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
// +build gofuzz
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
type attr interface {
|
||||
stun.Getter
|
||||
stun.Setter
|
||||
}
|
||||
|
||||
type attrs []struct {
|
||||
g attr
|
||||
t stun.AttrType
|
||||
}
|
||||
|
||||
func (a attrs) pick(v byte) struct {
|
||||
g attr
|
||||
t stun.AttrType
|
||||
} {
|
||||
idx := int(v) % len(a)
|
||||
return a[idx]
|
||||
}
|
||||
|
||||
func FuzzSetters(data []byte) int {
|
||||
var (
|
||||
m1 = &stun.Message{
|
||||
Raw: make([]byte, 0, 2048),
|
||||
}
|
||||
m2 = &stun.Message{
|
||||
Raw: make([]byte, 0, 2048),
|
||||
}
|
||||
m3 = &stun.Message{
|
||||
Raw: make([]byte, 0, 2048),
|
||||
}
|
||||
)
|
||||
attributes := attrs{
|
||||
{new(RequestedTransport), stun.AttrRequestedTransport},
|
||||
{new(RelayedAddress), stun.AttrXORRelayedAddress},
|
||||
{new(ChannelNumber), stun.AttrChannelNumber},
|
||||
{new(Data), stun.AttrData},
|
||||
{new(EvenPort), stun.AttrEvenPort},
|
||||
{new(Lifetime), stun.AttrLifetime},
|
||||
{new(ReservationToken), stun.AttrReservationToken},
|
||||
}
|
||||
var firstByte = byte(0)
|
||||
if len(data) > 0 {
|
||||
firstByte = data[0]
|
||||
}
|
||||
a := attributes.pick(firstByte)
|
||||
value := data
|
||||
if len(data) > 1 {
|
||||
value = value[1:]
|
||||
}
|
||||
m1.WriteHeader()
|
||||
m1.Add(a.t, value)
|
||||
err := a.g.GetFrom(m1)
|
||||
if err == stun.ErrAttributeNotFound {
|
||||
fmt.Println("unexpected 404") // nolint
|
||||
panic(err) // nolint
|
||||
}
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
m2.WriteHeader()
|
||||
if err := a.g.AddTo(m2); err != nil {
|
||||
fmt.Println("failed to add attribute to m2") // nolint
|
||||
panic(err) // nolint
|
||||
}
|
||||
m3.WriteHeader()
|
||||
v, err := m2.Get(a.t)
|
||||
if err != nil {
|
||||
panic(err) // nolint
|
||||
}
|
||||
m3.Add(a.t, v)
|
||||
|
||||
if !m2.Equal(m3) {
|
||||
fmt.Println(m2, "not equal", m3) // nolint
|
||||
panic("not equal") // nolint
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
var d = &ChannelData{}
|
||||
|
||||
func FuzzChannelData(data []byte) int {
|
||||
d.Reset()
|
||||
if b := bin.Uint16(data[0:4]); b > 20000 {
|
||||
bin.PutUint16(data[0:4], MinChannelNumber-1)
|
||||
} else if b > 40000 {
|
||||
bin.PutUint16(data[0:4], MinChannelNumber+(MaxChannelNumber-MinChannelNumber)%b)
|
||||
}
|
||||
d.Raw = append(d.Raw, data...)
|
||||
if d.Decode() != nil {
|
||||
return 0
|
||||
}
|
||||
d2 := &ChannelData{}
|
||||
d.Encode()
|
||||
if !d.Number.Valid() {
|
||||
return 1
|
||||
}
|
||||
d2.Raw = d.Raw
|
||||
if err := d2.Decode(); err != nil {
|
||||
panic(err) //nolint
|
||||
}
|
||||
return 1
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// DefaultLifetime in RFC 5766 is 10 minutes.
|
||||
//
|
||||
// RFC 5766 Section 2.2
|
||||
const DefaultLifetime = time.Minute * 10
|
||||
|
||||
// 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
|
||||
type Lifetime struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
// uint32 seconds
|
||||
const lifetimeSize = 4 // 4 bytes, 32 bits
|
||||
|
||||
// AddTo adds LIFETIME to message.
|
||||
func (l Lifetime) AddTo(m *stun.Message) error {
|
||||
v := make([]byte, lifetimeSize)
|
||||
binary.BigEndian.PutUint32(v, uint32(l.Seconds()))
|
||||
m.Add(stun.AttrLifetime, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFrom decodes LIFETIME from message.
|
||||
func (l *Lifetime) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrLifetime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stun.CheckSize(stun.AttrLifetime, len(v), lifetimeSize); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v[lifetimeSize-1] // asserting length
|
||||
seconds := binary.BigEndian.Uint32(v)
|
||||
l.Duration = time.Second * time.Duration(seconds)
|
||||
return nil
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// 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
|
||||
type PeerAddress struct {
|
||||
IP net.IP
|
||||
Port int
|
||||
}
|
||||
|
||||
func (a PeerAddress) String() string {
|
||||
return stun.XORMappedAddress(a).String()
|
||||
}
|
||||
|
||||
// AddTo adds XOR-PEER-ADDRESS to message.
|
||||
func (a PeerAddress) AddTo(m *stun.Message) error {
|
||||
return stun.XORMappedAddress(a).AddToAs(m, stun.AttrXORPeerAddress)
|
||||
}
|
||||
|
||||
// GetFrom decodes XOR-PEER-ADDRESS from message.
|
||||
func (a *PeerAddress) GetFrom(m *stun.Message) error {
|
||||
return (*stun.XORMappedAddress)(a).GetFromAs(m, stun.AttrXORPeerAddress)
|
||||
}
|
||||
|
||||
// XORPeerAddress 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
|
||||
type XORPeerAddress = PeerAddress
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Package proto implements RFC 5766 Traversal Using Relays around NAT.
|
||||
//
|
||||
// Merged from gortc/turn v0.80.
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// Default ports for TURN from RFC 5766 Section 4.
|
||||
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
|
||||
)
|
||||
|
||||
// CreatePermissionRequest is shorthand for create permission request type.
|
||||
func CreatePermissionRequest() stun.MessageType {
|
||||
return stun.NewType(stun.MethodCreatePermission, stun.ClassRequest)
|
||||
}
|
||||
|
||||
// AllocateRequest is shorthand for allocation request message type.
|
||||
func AllocateRequest() stun.MessageType { return stun.NewType(stun.MethodAllocate, stun.ClassRequest) }
|
||||
|
||||
// SendIndication is shorthand for send indication message type.
|
||||
func SendIndication() stun.MessageType { return stun.NewType(stun.MethodSend, stun.ClassIndication) }
|
||||
|
||||
// RefreshRequest is shorthand for refresh request message type.
|
||||
func RefreshRequest() stun.MessageType { return stun.NewType(stun.MethodRefresh, stun.ClassRequest) }
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// RelayedAddress implements XOR-RELAYED-ADDRESS attribute.
|
||||
//
|
||||
// It specifies the address and port that the server allocated to the
|
||||
// client. It is encoded in the same way as XOR-MAPPED-ADDRESS.
|
||||
//
|
||||
// RFC 5766 Section 14.5
|
||||
type RelayedAddress struct {
|
||||
IP net.IP
|
||||
Port int
|
||||
}
|
||||
|
||||
func (a RelayedAddress) String() string {
|
||||
return stun.XORMappedAddress(a).String()
|
||||
}
|
||||
|
||||
// AddTo adds XOR-PEER-ADDRESS to message.
|
||||
func (a RelayedAddress) AddTo(m *stun.Message) error {
|
||||
return stun.XORMappedAddress(a).AddToAs(m, stun.AttrXORRelayedAddress)
|
||||
}
|
||||
|
||||
// GetFrom decodes XOR-PEER-ADDRESS from message.
|
||||
func (a *RelayedAddress) GetFrom(m *stun.Message) error {
|
||||
return (*stun.XORMappedAddress)(a).GetFromAs(m, stun.AttrXORRelayedAddress)
|
||||
}
|
||||
|
||||
// XORRelayedAddress implements XOR-RELAYED-ADDRESS attribute.
|
||||
//
|
||||
// It specifies the address and port that the server allocated to the
|
||||
// client. It is encoded in the same way as XOR-MAPPED-ADDRESS.
|
||||
//
|
||||
// RFC 5766 Section 14.5
|
||||
type XORRelayedAddress = RelayedAddress
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// RequestedAddressFamily represents the REQUESTED-ADDRESS-FAMILY Attribute as
|
||||
// defined in RFC 6156 Section 4.1.1.
|
||||
type RequestedAddressFamily byte
|
||||
|
||||
const requestedFamilySize = 4
|
||||
|
||||
var errInvalidRequestedFamilyValue = errors.New("invalid value for requested family attribute")
|
||||
|
||||
// GetFrom decodes REQUESTED-ADDRESS-FAMILY from message.
|
||||
func (f *RequestedAddressFamily) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrRequestedAddressFamily)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stun.CheckSize(stun.AttrRequestedAddressFamily, len(v), requestedFamilySize); err != nil {
|
||||
return err
|
||||
}
|
||||
switch v[0] {
|
||||
case byte(RequestedFamilyIPv4), byte(RequestedFamilyIPv6):
|
||||
*f = RequestedAddressFamily(v[0])
|
||||
default:
|
||||
return errInvalidRequestedFamilyValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f RequestedAddressFamily) String() string {
|
||||
switch f {
|
||||
case RequestedFamilyIPv4:
|
||||
return "IPv4"
|
||||
case RequestedFamilyIPv6:
|
||||
return "IPv6"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// AddTo adds REQUESTED-ADDRESS-FAMILY to message.
|
||||
func (f RequestedAddressFamily) AddTo(m *stun.Message) error {
|
||||
v := make([]byte, requestedFamilySize)
|
||||
v[0] = byte(f)
|
||||
// b[1:4] is RFFU = 0.
|
||||
// The RFFU field MUST be set to zero on transmission and MUST be
|
||||
// ignored on reception. It is reserved for future uses.
|
||||
m.Add(stun.AttrRequestedAddressFamily, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Values for RequestedAddressFamily as defined in RFC 6156 Section 4.1.1.
|
||||
const (
|
||||
RequestedFamilyIPv4 RequestedAddressFamily = 0x01
|
||||
RequestedFamilyIPv6 RequestedAddressFamily = 0x02
|
||||
)
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
// Protocol is IANA assigned protocol number.
|
||||
type Protocol byte
|
||||
|
||||
const (
|
||||
// ProtoUDP is IANA assigned protocol number for UDP.
|
||||
ProtoUDP Protocol = 17
|
||||
)
|
||||
|
||||
func (p Protocol) String() string {
|
||||
switch p {
|
||||
case ProtoUDP:
|
||||
return "UDP"
|
||||
default:
|
||||
return strconv.Itoa(int(p))
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
type RequestedTransport struct {
|
||||
Protocol Protocol
|
||||
}
|
||||
|
||||
func (t RequestedTransport) String() string {
|
||||
return "protocol: " + t.Protocol.String()
|
||||
}
|
||||
|
||||
const requestedTransportSize = 4
|
||||
|
||||
// AddTo adds REQUESTED-TRANSPORT to message.
|
||||
func (t RequestedTransport) AddTo(m *stun.Message) error {
|
||||
v := make([]byte, requestedTransportSize)
|
||||
v[0] = byte(t.Protocol)
|
||||
// b[1:4] is RFFU = 0.
|
||||
// The RFFU field MUST be set to zero on transmission and MUST be
|
||||
// ignored on reception. It is reserved for future uses.
|
||||
m.Add(stun.AttrRequestedTransport, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFrom decodes REQUESTED-TRANSPORT from message.
|
||||
func (t *RequestedTransport) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrRequestedTransport)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stun.CheckSize(stun.AttrRequestedTransport, len(v), requestedTransportSize); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Protocol = Protocol(v[0])
|
||||
return nil
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package proto
|
||||
|
||||
import "github.com/pion/stun"
|
||||
|
||||
// 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
|
||||
type ReservationToken []byte
|
||||
|
||||
const reservationTokenSize = 8 // 8 bytes
|
||||
|
||||
// AddTo adds RESERVATION-TOKEN to message.
|
||||
func (t ReservationToken) AddTo(m *stun.Message) error {
|
||||
if err := stun.CheckSize(stun.AttrReservationToken, len(t), reservationTokenSize); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Add(stun.AttrReservationToken, t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFrom decodes RESERVATION-TOKEN from message.
|
||||
func (t *ReservationToken) GetFrom(m *stun.Message) error {
|
||||
v, err := m.Get(stun.AttrReservationToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stun.CheckSize(stun.AttrReservationToken, len(v), reservationTokenSize); err != nil {
|
||||
return err
|
||||
}
|
||||
*t = v
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user