Documentation ¶
Overview ¶
Package stun implements Session Traversal Utilities for NAT (STUN) RFC 5389.
The stun package is intended to use by package that implements extension to STUN (e.g. TURN) or client/server applications.
Most methods are designed to be zero allocations. If it is not enough, low-level methods are available. On other hand, there are helpers that reduce code repeat.
See examples for Message for basic usage, or https://github.com/ernado/turn package for example of stun extension implementation.
Index ¶
- Constants
- Variables
- func FingerprintValue(b []byte) uint32
- func IsMessage(b []byte) bool
- func NewTransactionID() (b [transactionIDSize]byte)
- type AlternateServer
- type AttrLengthError
- type AttrType
- type Attributes
- type CRCMismatch
- type Checker
- type DecodeErr
- type DecodeErrPlace
- type ErrorCode
- type ErrorCodeAttribute
- type FingerprintAttr
- type Getter
- type IntegrityErr
- type MappedAddress
- type Message
- func (m *Message) Add(t AttrType, v []byte)
- func (m *Message) Build(setters ...Setter) error
- func (m *Message) Check(checkers ...Checker) error
- func (m *Message) Contains(t AttrType) bool
- func (m *Message) Decode() error
- func (m *Message) Encode()
- func (m *Message) Equal(b *Message) bool
- func (m *Message) Get(t AttrType) ([]byte, error)
- func (m *Message) NewTransactionID() error
- func (m *Message) Parse(getters ...Getter) error
- func (m *Message) ReadFrom(r io.Reader) (int64, error)
- func (m *Message) Reset()
- func (m *Message) SetType(t MessageType)
- func (m *Message) String() string
- func (m *Message) Write(tBuf []byte) (int, error)
- func (m *Message) WriteAttributes()
- func (m *Message) WriteHeader()
- func (m *Message) WriteLength()
- func (m *Message) WriteTo(w io.Writer) (int64, error)
- func (m *Message) WriteTransactionID()
- func (m *Message) WriteType()
- type MessageClass
- type MessageIntegrity
- type MessageType
- type Method
- type Nonce
- type RawAttribute
- type Realm
- type Setter
- type Software
- type TextAttribute
- type UnknownAttributes
- type Username
- type XORMappedAddress
Examples ¶
Constants ¶
const ( DefaultPort = 3478 DefaultTLSPort = 5349 )
IANA assigned ports for "stun" protocol/
Variables ¶
var ( // Binding request message type. BindingRequest = NewType(MethodBinding, ClassRequest) // Binding success response message type BindingSuccess = NewType(MethodBinding, ClassSuccessResponse) // Binding error response message type. BindingError = NewType(MethodBinding, ClassErrorResponse) )
Common STUN message types.
var ErrAttributeNotFound = errors.New("Attribute not found")
ErrAttributeNotFound means that attribute with provided attribute type does not exist in message.
var ErrBadIPLength = errors.New("invalid length of IP value")
ErrBadIPLength means that len(IP) is not net.{IPv6len,IPv4len}.
var ErrBadUnknownAttrsSize = errors.New("bad UNKNOWN-ATTRIBUTES size")
ErrBadUnknownAttrsSize means that UNKNOWN-ATTRIBUTES attribute value has invalid length.
var ErrFingerprintBeforeIntegrity = errors.New(
"FINGERPRINT before MESSAGE-INTEGRITY attribute",
)
ErrFingerprintBeforeIntegrity means that FINGEPRINT attribute is already in message, so MESSAGE-INTEGRITY attribute cannot be added.
var ErrNoDefaultReason = errors.New("No default reason for ErrorCode")
ErrNoDefaultReason means that default reason for provided error code is not defined in RFC.
var ErrReasonLengthTooBig = errors.New("reason for ERROR-CODE is too big")
ErrReasonLengthTooBig means that len(Reason) > 763 bytes.
var ErrUnexpectedHeaderEOF = errors.New("unexpected EOF: not enough bytes to read header")
ErrUnexpectedHeaderEOF means that there were not enough bytes in m.Raw to read header.
Functions ¶
func FingerprintValue ¶
FingerprintValue returns CRC-32 of b XOR-ed by 0x5354554e.
The value of the attribute is computed as the CRC-32 of the STUN message up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with the 32-bit value 0x5354554e (the XOR helps in cases where an application packet is also using CRC-32 in it).
func IsMessage ¶
IsMessage returns true if b looks like STUN message. Useful for multiplexing. IsMessage does not guarantee that decoding will be successful.
func NewTransactionID ¶
func NewTransactionID() (b [transactionIDSize]byte)
NewTransactionID returns new random transaction ID using crypto/rand as source.
Types ¶
type AlternateServer ¶
AlternateServer represents ALTERNATE-SERVER attribute.
https://tools.ietf.org/html/rfc5389#section-15.11
func (*AlternateServer) AddTo ¶
func (s *AlternateServer) AddTo(m *Message) error
AddTo adds ALTERNATE-SERVER attribute to message.
func (*AlternateServer) GetFrom ¶
func (s *AlternateServer) GetFrom(m *Message) error
GetFrom decodes ALTERNATE-SERVER from message.
type AttrLengthError ¶
AttrLengthError occurs when len(v) > Max.
func (AttrLengthError) Error ¶
func (e AttrLengthError) Error() string
type AttrType ¶
type AttrType uint16
AttrType is attribute type.
const ( AttrMappedAddress AttrType = 0x0001 // MAPPED-ADDRESS AttrUsername AttrType = 0x0006 // USERNAME AttrMessageIntegrity AttrType = 0x0008 // MESSAGE-INTEGRITY AttrErrorCode AttrType = 0x0009 // ERROR-CODE AttrUnknownAttributes AttrType = 0x000A // UNKNOWN-ATTRIBUTES AttrRealm AttrType = 0x0014 // REALM AttrNonce AttrType = 0x0015 // NONCE AttrXORMappedAddress AttrType = 0x0020 // XOR-MAPPED-ADDRESS )
Attributes from comprehension-required range (0x0000-0x7FFF).
const ( AttrSoftware AttrType = 0x8022 // SOFTWARE AttrAlternateServer AttrType = 0x8023 // ALTERNATE-SERVER AttrFingerprint AttrType = 0x8028 // FINGERPRINT )
Attributes from comprehension-optional range (0x8000-0xFFFF).
const ( AttrPriority AttrType = 0x0024 // PRIORITY AttrUseCandidate AttrType = 0x0025 // USE-CANDIDATE AttrICEControlled AttrType = 0x8029 // ICE-CONTROLLED AttrICEControlling AttrType = 0x802A // ICE-CONTROLLING )
Attributes from RFC 5245 ICE.
const ( AttrChannelNumber AttrType = 0x000C // CHANNEL-NUMBER AttrLifetime AttrType = 0x000D // LIFETIME AttrXORPeerAddress AttrType = 0x0012 // XOR-PEER-ADDRESS AttrData AttrType = 0x0013 // DATA AttrXORRelayedAddress AttrType = 0x0016 // XOR-RELAYED-ADDRESS AttrEvenPort AttrType = 0x0018 // EVEN-PORT AttrRequestedTransport AttrType = 0x0019 // REQUESTED-TRANSPORT AttrDontFragment AttrType = 0x001A // DONT-FRAGMENT AttrReservationToken AttrType = 0x0022 // RESERVATION-TOKEN )
Attributes from RFC 5766 TURN.
const (
AttrOrigin AttrType = 0x802F
)
Attributes from An Origin Attribute for the STUN Protocol.
type Attributes ¶
type Attributes []RawAttribute
Attributes is list of message attributes.
func (Attributes) Get ¶
func (a Attributes) Get(t AttrType) (RawAttribute, bool)
Get returns first attribute from list by the type. If attribute is present the RawAttribute is returned and the boolean is true. Otherwise the returned RawAttribute will be empty and boolean will be false.
type CRCMismatch ¶
CRCMismatch represents CRC check error.
func (CRCMismatch) Error ¶
func (m CRCMismatch) Error() string
type DecodeErr ¶
type DecodeErr struct { Place DecodeErrPlace Message string }
DecodeErr records an error and place when it is occurred.
func (DecodeErr) IsInvalidCookie ¶
IsInvalidCookie returns true if error means that magic cookie value is invalid.
func (DecodeErr) IsPlace ¶
func (e DecodeErr) IsPlace(p DecodeErrPlace) bool
IsPlace reports if error place is p.
func (DecodeErr) IsPlaceChildren ¶
IsPlaceChildren reports if error place children is c.
func (DecodeErr) IsPlaceParent ¶
IsPlaceParent reports if error place parent is p.
type DecodeErrPlace ¶
DecodeErrPlace records a place where error is occurred.
func (DecodeErrPlace) String ¶
func (p DecodeErrPlace) String() string
type ErrorCode ¶
type ErrorCode int
ErrorCode is code for ERROR-CODE attribute.
const ( CodeTryAlternate ErrorCode = 300 CodeBadRequest ErrorCode = 400 CodeUnknownAttribute ErrorCode = 420 CodeStaleNonce ErrorCode = 428 CodeRoleConflict ErrorCode = 478 CodeServerError ErrorCode = 500 )
Possible error codes.
const ( CodeForbidden ErrorCode = 403 // Forbidden CodeAllocMismatch ErrorCode = 437 // Allocation Mismatch CodeWrongCredentials ErrorCode = 441 // Wrong Credentials CodeUnsupportedTransProto ErrorCode = 442 // Unsupported Transport Protocol CodeAllocQuotaReached ErrorCode = 486 // Allocation Quota Reached CodeInsufficientCapacity ErrorCode = 508 // Insufficient Capacity )
Error codes from RFC 5766.
type ErrorCodeAttribute ¶
ErrorCodeAttribute represents ERROR-CODE attribute.
https://tools.ietf.org/html/rfc5389#section-15.6
func (ErrorCodeAttribute) AddTo ¶
func (c ErrorCodeAttribute) AddTo(m *Message) error
AddTo adds ERROR-CODE to m.
func (*ErrorCodeAttribute) GetFrom ¶
func (c *ErrorCodeAttribute) GetFrom(m *Message) error
GetFrom decodes ERROR-CODE from m. Reason is valid until m.Raw is valid.
func (ErrorCodeAttribute) String ¶
func (c ErrorCodeAttribute) String() string
type FingerprintAttr ¶
type FingerprintAttr byte
FingerprintAttr represents FINGERPRINT attribute.
https://tools.ietf.org/html/rfc5389#section-15.5
var Fingerprint FingerprintAttr
Fingerprint is shorthand for FingerprintAttr.
Example:
m := New() Fingerprint.AddTo(m)
func (FingerprintAttr) AddTo ¶
func (FingerprintAttr) AddTo(m *Message) error
AddTo adds fingerprint to message.
func (FingerprintAttr) Check ¶
func (FingerprintAttr) Check(m *Message) error
Check reads fingerprint value from m and checks it, returning error if any. Can return *DecodeErr, ErrAttributeNotFound, and *CRCMismatch.
type IntegrityErr ¶
IntegrityErr occurs when computed HMAC differs from expected.
func (*IntegrityErr) Error ¶
func (i *IntegrityErr) Error() string
type MappedAddress ¶
MappedAddress represents MAPPED-ADDRESS attribute.
This attribute is used only by servers for achieving backwards compatibility with RFC 3489 clients.
https://tools.ietf.org/html/rfc5389#section-15.1
func (*MappedAddress) AddTo ¶
func (a *MappedAddress) AddTo(m *Message) error
AddTo adds MAPPED-ADDRESS to message.
func (*MappedAddress) GetFrom ¶
func (a *MappedAddress) GetFrom(m *Message) error
GetFrom decodes MAPPED-ADDRESS from message.
func (MappedAddress) String ¶
func (a MappedAddress) String() string
type Message ¶
type Message struct { Type MessageType Length uint32 // len(Raw) not including header TransactionID [transactionIDSize]byte Attributes Attributes Raw []byte }
Message represents a single STUN packet. It uses aggressive internal buffering to enable zero-allocation encoding and decoding, so there are some usage constraints:
Message, its fields, results of m.Get or any attribute a.GetFrom are valid only until Message.Raw is not modified.
Example ¶
buf := new(bytes.Buffer) m := new(Message) m.Build(BindingRequest, NewTransactionIDSetter([transactionIDSize]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, }), NewSoftware("ernado/stun"), NewLongTermIntegrity("username", "realm", "password"), Fingerprint, ) // Instead of calling Build, use AddTo(m) directly for all setters // that are available before. // For example: // software := NewSoftware("ernado/stun") // software.AddTo(m) // no allocations // Or pass software as follows: // m.Build(&software) // no allocations // If you pass software as value, there will be 1 allocation. // This rule is correct for all setters. fmt.Println(m, "buff length:", len(m.Raw)) n, err := m.WriteTo(buf) fmt.Println("wrote", n, "err", err) // Decoding from buf new *Message. decoded := new(Message) decoded.Raw = make([]byte, 0, 1024) // for ReadFrom that reuses m.Raw // ReadFrom does not allocate internal buffer for reading from io.Reader, // instead it uses m.Raw, expanding it length to capacity. decoded.ReadFrom(buf) fmt.Println("has software:", decoded.Contains(AttrSoftware)) fmt.Println("has nonce:", decoded.Contains(AttrNonce)) var software Software decoded.Parse(&software) // or software.GetFrom(decoded) // Rule for Parse method is same as for Build. fmt.Println("software:", software) if err := Fingerprint.Check(decoded); err == nil { fmt.Println("fingerprint is correct") } else { fmt.Println("fingerprint is incorrect:", err) } // Checking integrity i := NewLongTermIntegrity("username", "realm", "password") if err := i.Check(decoded); err == nil { fmt.Println("integrity ok") } else { fmt.Println("integrity bad:", err) } fmt.Println("for corrupted message:") decoded.Raw[22] = 33 fmt.Println("fingerprint:", Fingerprint.Check(decoded)) iErr, ok := i.Check(decoded).(*IntegrityErr) if ok { fmt.Println("integrity check failed") fmt.Printf("got: %x\n", iErr.Actual) fmt.Printf("want: %x\n", iErr.Expected) } else { fmt.Println("assertion failed") }
Output: binding request l=48 attrs=3 id=AQIDBAUGBwgJAAEA buff length: 68 wrote 68 err <nil> has software: true has nonce: false software: ernado/stun fingerprint is correct integrity ok for corrupted message: fingerprint: CRC mismatch: b36d2c38 (expected) != 8ef13141 (actual) integrity check failed got: 06f0692c159f4256c14b9442927889e341256ac2 want: c1105962efee5c96f4f194cc91b4eb8ab7667c7a
func (*Message) Add ¶
Add appends new attribute to message. Not goroutine-safe.
Value of attribute is copied to internal buffer so it is safe to reuse v.
func (*Message) Build ¶
Build resets message and applies setters to it in batch, returning on first error. To prevent allocations, pass pointers to values.
Example:
var ( t = BindingRequest username = NewUsername("username") nonce = NewNonce("nonce") realm = NewRealm("example.org") ) m := new(Message) m.Build(t, username, nonce, realm) // 4 allocations m.Build(&t, &username, &nonce, &realm) // 0 allocations
See BenchmarkBuildOverhead.
func (*Message) Encode ¶
func (m *Message) Encode()
Encode resets m.Raw and calls WriteHeader and WriteAttributes.
func (*Message) Get ¶
Get returns byte slice that represents attribute value, if there is no attribute with such type, ErrAttributeNotFound is returned.
func (*Message) NewTransactionID ¶
NewTransactionID sets m.TransactionID to random value from crypto/rand and returns error if any.
func (*Message) ReadFrom ¶
ReadFrom implements ReaderFrom. Reads message from r into m.Raw, Decodes it and return error if any. If m.Raw is too small, will return ErrUnexpectedEOF, ErrUnexpectedHeaderEOF or *DecodeErr.
Can return *DecodeErr while decoding too.
func (*Message) Reset ¶
func (m *Message) Reset()
Reset resets Message, attributes and underlying buffer length.
func (*Message) SetType ¶
func (m *Message) SetType(t MessageType)
SetType sets m.Type and writes it to m.Raw.
func (*Message) Write ¶
Write decodes message and return error if any.
Any error is unrecoverable, but message could be partially decoded.
func (*Message) WriteAttributes ¶
func (m *Message) WriteAttributes()
WriteAttributes encodes all m.Attributes to m.
func (*Message) WriteHeader ¶
func (m *Message) WriteHeader()
WriteHeader writes header to underlying buffer. Not goroutine-safe.
func (*Message) WriteLength ¶
func (m *Message) WriteLength()
WriteLength writes m.Length to m.Raw. Call is valid only if len(m.Raw) >= 4.
func (*Message) WriteTo ¶
WriteTo implements WriterTo via calling Write(m.Raw) on w and returning call result.
func (*Message) WriteTransactionID ¶
func (m *Message) WriteTransactionID()
WriteTransactionID writes m.TransactionID to m.Raw.
type MessageClass ¶
type MessageClass byte
MessageClass is 8-bit representation of 2-bit class of STUN Message Class.
const ( ClassRequest MessageClass = 0x00 // 0b00 ClassIndication MessageClass = 0x01 // 0b01 ClassSuccessResponse MessageClass = 0x02 // 0b10 ClassErrorResponse MessageClass = 0x03 // 0b11 )
Possible values for message class in STUN Message Type.
func (MessageClass) String ¶
func (c MessageClass) String() string
type MessageIntegrity ¶
type MessageIntegrity []byte
MessageIntegrity represents MESSAGE-INTEGRITY attribute. AddTo and GetFrom methods will allocate memory for cryptographic functions. Zero-allocation version of MessageIntegrity is not implemented. Implementation and changes to it is subject to security review.
https://tools.ietf.org/html/rfc5389#section-15.4
func NewLongTermIntegrity ¶
func NewLongTermIntegrity(username, realm, password string) MessageIntegrity
NewLongTermIntegrity returns new MessageIntegrity with key for long-term credentials. Password, username, and realm must be SASL-prepared.
func NewShortTermIntegrity ¶
func NewShortTermIntegrity(password string) MessageIntegrity
NewShortTermIntegrity returns new MessageIntegrity with key for short-term credentials. Password must be SASL-prepared.
func (MessageIntegrity) AddTo ¶
func (i MessageIntegrity) AddTo(m *Message) error
AddTo adds MESSAGE-INTEGRITY attribute to message. Be advised, CPU and allocations costly, can be cause of DOS.
func (MessageIntegrity) Check ¶
func (i MessageIntegrity) Check(m *Message) error
Check checks MESSAGE-INTEGRITY attribute. Be advised, CPU and allocations costly, can be cause of DOS.
func (MessageIntegrity) String ¶
func (i MessageIntegrity) String() string
type MessageType ¶
type MessageType struct { Method Method // e.g. binding Class MessageClass // e.g. request }
MessageType is STUN Message Type Field.
func NewType ¶
func NewType(method Method, class MessageClass) MessageType
NewType returns new message type with provided method and class.
func (*MessageType) ReadValue ¶
func (t *MessageType) ReadValue(v uint16)
ReadValue decodes uint16 into MessageType.
func (MessageType) String ¶
func (t MessageType) String() string
func (MessageType) Value ¶
func (t MessageType) Value() uint16
Value returns bit representation of messageType.
type Method ¶
type Method uint16
Method is uint16 representation of 12-bit STUN method.
type RawAttribute ¶
RawAttribute is a Type-Length-Value (TLV) object that can be added to a STUN message. Attributes are divided into two types: comprehension-required and comprehension-optional. STUN agents can safely ignore comprehension-optional attributes they don't understand, but cannot successfully process a message if it contains comprehension-required attributes that are not understood.
func (RawAttribute) Equal ¶
func (a RawAttribute) Equal(b RawAttribute) bool
Equal returns true if a == b.
func (RawAttribute) String ¶
func (a RawAttribute) String() string
type Realm ¶
type Realm []byte
Realm represents REALM attribute.
type Setter ¶
Setter sets *Message attribute.
func NewTransactionIDSetter ¶
NewTransactionIDSetter returns new Setter that sets message transaction id to provided value.
type Software ¶
type Software []byte
Software is SOFTWARE attribute.
https://tools.ietf.org/html/rfc5389#section-15.10
func NewSoftware ¶
NewSoftware returns *Software from string.
type TextAttribute ¶
type TextAttribute []byte
TextAttribute is helper for adding and getting text attributes.
type UnknownAttributes ¶
type UnknownAttributes []AttrType
UnknownAttributes represents UNKNOWN-ATTRIBUTES attribute.
https://tools.ietf.org/html/rfc5389#section-15.9
func (UnknownAttributes) AddTo ¶
func (a UnknownAttributes) AddTo(m *Message) error
AddTo adds UNKNOWN-ATTRIBUTES attribute to message.
func (*UnknownAttributes) GetFrom ¶
func (a *UnknownAttributes) GetFrom(m *Message) error
GetFrom parses UNKNOWN-ATTRIBUTES from message.
func (UnknownAttributes) String ¶
func (a UnknownAttributes) String() string
type Username ¶
type Username []byte
Username represents USERNAME attribute.
https://tools.ietf.org/html/rfc5389#section-15.3
func NewUsername ¶
NewUsername returns Username with provided value.
type XORMappedAddress ¶
XORMappedAddress implements XOR-MAPPED-ADDRESS attribute.
https://tools.ietf.org/html/rfc5389#section-15.2
func (XORMappedAddress) AddTo ¶
func (a XORMappedAddress) AddTo(m *Message) error
AddTo adds XOR-MAPPED-ADDRESS to m. Can return ErrBadIPLength if len(a.IP) is invalid.
func (XORMappedAddress) AddToAs ¶
func (a XORMappedAddress) AddToAs(m *Message, t AttrType) error
AddToAs adds XOR-MAPPED-ADDRESS value to m as t attribute.
func (*XORMappedAddress) GetFrom ¶
func (a *XORMappedAddress) GetFrom(m *Message) error
GetFrom decodes XOR-MAPPED-ADDRESS attribute in message and returns error if any. While decoding, a.IP is reused if possible and can be rendered to invalid state (e.g. if a.IP was set to IPv6 and then IPv4 value were decoded into it), be careful.
Example:
expectedIP := net.ParseIP("213.141.156.236") expectedIP.String() // 213.141.156.236, 16 bytes, first 12 of them are zeroes expectedPort := 21254 addr := &XORMappedAddress{ IP: expectedIP, Port: expectedPort, } // addr were added to message that is decoded as newMessage // ... addr.GetFrom(newMessage) addr.IP.String() // 213.141.156.236, net.IPv4Len expectedIP.String() // d58d:9cec::ffff:d58d:9cec, 16 bytes, first 4 are IPv4 // now we have len(expectedIP) = 16 and len(addr.IP) = 4.
func (*XORMappedAddress) GetFromAs ¶
func (a *XORMappedAddress) GetFromAs(m *Message, t AttrType) error
GetFromAs decodes XOR-MAPPED-ADDRESS attribute value in message getting it as for t type.
func (XORMappedAddress) String ¶
func (a XORMappedAddress) String() string