stun

package module
Version: v0.3.5 Latest Latest
Warning

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

Go to latest
Published: May 29, 2020 License: MIT Imports: 19 Imported by: 35

README


Pion STUN

A Go implementation of STUN

Pion stun Slack Widget
Build Status GoDoc Coverage Status Go Report Card


Roadmap

The library is used as a part of our WebRTC implementation. Please refer to that roadmap to track our major milestones.

Community

Pion has an active community on the Golang Slack. Sign up and join the #pion channel for discussions and support. You can also use Pion mailing list.

We are always looking to support your projects. Please reach out if you have something to build!

If you need commercial support or don't want to use public methods you can contact us at team@pion.ly

Contributing

Check out the contributing wiki to join the group of amazing people making this project possible:

STUN

Package stun implements Session Traversal Utilities for NAT (STUN) [RFC5389] protocol and client with no external dependencies and zero allocations in hot paths. Client supports automatic request retransmissions.

Example

You can get your current IP address from any STUN server by sending binding request. See more idiomatic example at cmd/stun-client.

package main

import (
	"fmt"

	"github.com/pion/stun"
)

func main() {
	// Creating a "connection" to STUN server.
	c, err := stun.Dial("udp", "stun.l.google.com:19302")
	if err != nil {
		panic(err)
	}
	// Building binding request with random transaction id.
	message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
	// Sending request to STUN server, waiting for response message.
	if err := c.Do(message, func(res stun.Event) {
		if res.Error != nil {
			panic(res.Error)
		}
		// Decoding XOR-MAPPED-ADDRESS attribute from message.
		var xorAddr stun.XORMappedAddress
		if err := xorAddr.GetFrom(res.Message); err != nil {
			panic(err)
		}
		fmt.Println("your IP is", xorAddr.IP)
	}); err != nil {
		panic(err)
	}
}

Supported RFCs

Stability

Package is currently stable, no backward incompatible changes are expected with exception of critical bugs or security fixes.

Additional attributes are unlikely to be implemented in scope of stun package, the only exception is constants for attribute or message types.

RFC 3489 notes

RFC 5389 obsoletes RFC 3489, so implementation was ignored by purpose, however, RFC 3489 can be easily implemented as separate package.

Requirements

Go 1.12 is currently supported and tested in CI.

Testing

Client behavior is tested and verified in many ways:

  • End-To-End with long-term credentials
    • coturn: The coturn server (linux)
  • Bunch of code static checkers (linters)
  • Standard unit-tests with coverage reporting (linux {amd64, arm64}, windows and darwin)
  • Explicit API backward compatibility check, see api directory

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

Benchmarks

Intel(R) Core(TM) i7-8700K:

version: 1.16.5
goos: linux
goarch: amd64
pkg: github.com/pion/stun
PASS
benchmark                                         iter       time/iter      throughput   bytes alloc        allocs
---------                                         ----       ---------      ----------   -----------        ------
BenchmarkMappedAddress_AddTo-12               30000000     36.40 ns/op                        0 B/op   0 allocs/op
BenchmarkAlternateServer_AddTo-12             50000000     36.70 ns/op                        0 B/op   0 allocs/op
BenchmarkAgent_GC-12                            500000   2552.00 ns/op                        0 B/op   0 allocs/op
BenchmarkAgent_Process-12                     50000000     38.00 ns/op                        0 B/op   0 allocs/op
BenchmarkMessage_GetNotFound-12              200000000      6.90 ns/op                        0 B/op   0 allocs/op
BenchmarkMessage_Get-12                      200000000      7.61 ns/op                        0 B/op   0 allocs/op
BenchmarkClient_Do-12                          2000000   1072.00 ns/op                        0 B/op   0 allocs/op
BenchmarkErrorCode_AddTo-12                   20000000     67.00 ns/op                        0 B/op   0 allocs/op
BenchmarkErrorCodeAttribute_AddTo-12          30000000     52.20 ns/op                        0 B/op   0 allocs/op
BenchmarkErrorCodeAttribute_GetFrom-12       100000000     12.00 ns/op                        0 B/op   0 allocs/op
BenchmarkFingerprint_AddTo-12                 20000000    102.00 ns/op     430.08 MB/s        0 B/op   0 allocs/op
BenchmarkFingerprint_Check-12                 30000000     54.80 ns/op     948.38 MB/s        0 B/op   0 allocs/op
BenchmarkBuildOverhead/Build-12                5000000    333.00 ns/op                        0 B/op   0 allocs/op
BenchmarkBuildOverhead/BuildNonPointer-12      3000000    536.00 ns/op                      100 B/op   4 allocs/op
BenchmarkBuildOverhead/Raw-12                 10000000    181.00 ns/op                        0 B/op   0 allocs/op
BenchmarkMessageIntegrity_AddTo-12             1000000   1053.00 ns/op      18.98 MB/s        0 B/op   0 allocs/op
BenchmarkMessageIntegrity_Check-12             1000000   1135.00 ns/op      28.17 MB/s        0 B/op   0 allocs/op
BenchmarkMessage_Write-12                    100000000     27.70 ns/op    1011.09 MB/s        0 B/op   0 allocs/op
BenchmarkMessageType_Value-12               2000000000      0.49 ns/op                        0 B/op   0 allocs/op
BenchmarkMessage_WriteTo-12                  100000000     12.80 ns/op                        0 B/op   0 allocs/op
BenchmarkMessage_ReadFrom-12                  50000000     25.00 ns/op     801.19 MB/s        0 B/op   0 allocs/op
BenchmarkMessage_ReadBytes-12                100000000     18.00 ns/op    1113.03 MB/s        0 B/op   0 allocs/op
BenchmarkIsMessage-12                       2000000000      1.08 ns/op   18535.57 MB/s        0 B/op   0 allocs/op
BenchmarkMessage_NewTransactionID-12           2000000    673.00 ns/op                        0 B/op   0 allocs/op
BenchmarkMessageFull-12                        5000000    316.00 ns/op                        0 B/op   0 allocs/op
BenchmarkMessageFullHardcore-12               20000000     88.90 ns/op                        0 B/op   0 allocs/op
BenchmarkMessage_WriteHeader-12              200000000      8.18 ns/op                        0 B/op   0 allocs/op
BenchmarkMessage_CloneTo-12                   30000000     37.90 ns/op    1795.32 MB/s        0 B/op   0 allocs/op
BenchmarkMessage_AddTo-12                    300000000      4.77 ns/op                        0 B/op   0 allocs/op
BenchmarkDecode-12                           100000000     22.00 ns/op                        0 B/op   0 allocs/op
BenchmarkUsername_AddTo-12                    50000000     23.20 ns/op                        0 B/op   0 allocs/op
BenchmarkUsername_GetFrom-12                 100000000     17.90 ns/op                        0 B/op   0 allocs/op
BenchmarkNonce_AddTo-12                       50000000     34.40 ns/op                        0 B/op   0 allocs/op
BenchmarkNonce_AddTo_BadLength-12            200000000      8.29 ns/op                        0 B/op   0 allocs/op
BenchmarkNonce_GetFrom-12                    100000000     17.50 ns/op                        0 B/op   0 allocs/op
BenchmarkUnknownAttributes/AddTo-12           30000000     48.10 ns/op                        0 B/op   0 allocs/op
BenchmarkUnknownAttributes/GetFrom-12        100000000     20.90 ns/op                        0 B/op   0 allocs/op
BenchmarkXOR-12                               50000000     25.80 ns/op   39652.86 MB/s        0 B/op   0 allocs/op
BenchmarkXORSafe-12                            3000000    515.00 ns/op    1988.04 MB/s        0 B/op   0 allocs/op
BenchmarkXORFast-12                           20000000     73.40 ns/op   13959.30 MB/s        0 B/op   0 allocs/op
BenchmarkXORMappedAddress_AddTo-12            20000000     56.70 ns/op                        0 B/op   0 allocs/op
BenchmarkXORMappedAddress_GetFrom-12          50000000     37.40 ns/op                        0 B/op   0 allocs/op
ok  	github.com/pion/stun	76.868s

License

MIT License - see LICENSE for full text

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/pion/turn package for example of stun extension implementation.

Index

Examples

Constants

View Source
const (
	DefaultPort    = 3478
	DefaultTLSPort = 5349
)

IANA assigned ports for "stun" protocol.

View Source
const (
	// DEPRECATED, use CodeUnauthorized.
	CodeUnauthorised = CodeUnauthorized
)

DEPRECATED constants.

View Source
const (

	// TransactionIDSize is length of transaction id array (in bytes).
	TransactionIDSize = 12 // 96 bit
)

Variables

View Source
var (
	// ErrTransactionStopped indicates that transaction was manually stopped.
	ErrTransactionStopped = errors.New("transaction is stopped")
	// ErrTransactionNotExists indicates that agent failed to find transaction.
	ErrTransactionNotExists = errors.New("transaction not exists")
	// ErrTransactionExists indicates that transaction with same id is already
	// registered.
	ErrTransactionExists = errors.New("transaction exists with same id")
)
View Source
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.

View Source
var ErrAgentClosed = errors.New("agent is closed")

ErrAgentClosed indicates that agent is in closed state and is unable to handle transactions.

View Source
var ErrAttributeNotFound = errors.New("attribute not found")

ErrAttributeNotFound means that attribute with provided attribute type does not exist in message.

View Source
var ErrAttributeSizeInvalid = errors.New("attribute size is invalid")

ErrAttributeSizeInvalid means that decoded attribute size is invalid.

View Source
var ErrAttributeSizeOverflow = errors.New("attribute size overflow")

ErrAttributeSizeOverflow means that decoded attribute size is too big.

View Source
var ErrBadIPLength = errors.New("invalid length of IP value")

ErrBadIPLength means that len(IP) is not net.{IPv6len,IPv4len}.

View Source
var ErrBadUnknownAttrsSize = errors.New("bad UNKNOWN-ATTRIBUTES size")

ErrBadUnknownAttrsSize means that UNKNOWN-ATTRIBUTES attribute value has invalid length.

View Source
var ErrClientClosed = errors.New("client is closed")

ErrClientClosed indicates that client is closed.

View Source
var ErrClientNotInitialized = errors.New("client not initialized")

ErrClientNotInitialized means that client connection or agent is nil.

View Source
var ErrDecodeToNil = errors.New("attempt to decode to nil message")

ErrDecodeToNil occurs on Decode(data, nil) call.

View Source
var ErrFingerprintBeforeIntegrity = errors.New("FINGERPRINT before MESSAGE-INTEGRITY attribute")

ErrFingerprintBeforeIntegrity means that FINGERPRINT attribute is already in message, so MESSAGE-INTEGRITY attribute cannot be added.

View Source
var ErrFingerprintMismatch = errors.New("fingerprint check failed")

ErrFingerprintMismatch means that computed fingerprint differs from expected.

View Source
var ErrIntegrityMismatch = errors.New("integrity check failed")

ErrIntegrityMismatch means that computed HMAC differs from expected.

View Source
var ErrNoConnection = errors.New("no connection provided")

ErrNoConnection means that ClientOptions.Connection is nil.

View Source
var ErrNoDefaultReason = errors.New("no default reason for ErrorCode")

ErrNoDefaultReason means that default reason for provided error code is not defined in RFC.

View Source
var ErrTransactionTimeOut = errors.New("transaction is timed out")

ErrTransactionTimeOut indicates that transaction has reached deadline.

View Source
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 CheckOverflow added in v0.3.0

func CheckOverflow(_ AttrType, got, max int) error

CheckOverflow returns ErrAttributeSizeOverflow if got is bigger that max.

func CheckSize added in v0.3.0

func CheckSize(_ AttrType, got, expected int) error

CheckSize returns ErrAttrSizeInvalid if got is not equal to expected.

func Decode added in v0.3.0

func Decode(data []byte, m *Message) error

Decode decodes Message from data to m, returning error if any.

func FingerprintValue added in v0.3.0

func FingerprintValue(b []byte) uint32

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 IsAttrSizeInvalid added in v0.3.0

func IsAttrSizeInvalid(err error) bool

IsAttrSizeInvalid returns true if error means that attribute size is invalid.

func IsAttrSizeOverflow added in v0.3.0

func IsAttrSizeOverflow(err error) bool

IsAttrSizeOverflow returns true if error means that attribute size is too big.

func IsMessage added in v0.3.0

func IsMessage(b []byte) bool

IsMessage returns true if b looks like STUN message. Useful for multiplexing. IsMessage does not guarantee that decoding will be successful.

func NewTransactionID added in v0.3.0

func NewTransactionID() (b [TransactionIDSize]byte)

NewTransactionID returns new random transaction ID using crypto/rand as source.

func WithNoRetransmit added in v0.3.0

func WithNoRetransmit(c *Client)

WithNoRetransmit disables retransmissions and sets RTO to defaultMaxAttempts * defaultRTO which will be effectively time out if not set.

Useful for TCP connections where transport handles RTO.

Types

type Agent added in v0.3.0

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

Agent is low-level abstraction over transaction list that handles concurrency (all calls are goroutine-safe) and time outs (via Collect call).

func NewAgent added in v0.3.0

func NewAgent(h Handler) *Agent

NewAgent initializes and returns new Agent with provided handler. If h is nil, the NoopHandler will be used.

func (*Agent) Close added in v0.3.0

func (a *Agent) Close() error

Close terminates all transactions with ErrAgentClosed and renders Agent to closed state.

func (*Agent) Collect added in v0.3.0

func (a *Agent) Collect(gcTime time.Time) error

Collect terminates all transactions that have deadline before provided time, blocking until all handlers will process ErrTransactionTimeOut. Will return ErrAgentClosed if agent is already closed.

It is safe to call Collect concurrently but makes no sense.

func (*Agent) Process added in v0.3.0

func (a *Agent) Process(m *Message) error

Process incoming message, synchronously passing it to handler.

func (*Agent) SetHandler added in v0.3.0

func (a *Agent) SetHandler(h Handler) error

SetHandler sets agent handler to h.

func (*Agent) Start added in v0.3.0

func (a *Agent) Start(id [TransactionIDSize]byte, deadline time.Time) error

Start registers transaction with provided id and deadline. Could return ErrAgentClosed, ErrTransactionExists.

Agent handler is guaranteed to be eventually called.

func (*Agent) Stop added in v0.3.0

func (a *Agent) Stop(id [TransactionIDSize]byte) error

Stop stops transaction by id with ErrTransactionStopped, blocking until handler returns.

func (*Agent) StopWithError added in v0.3.0

func (a *Agent) StopWithError(id [TransactionIDSize]byte, err error) error

StopWithError removes transaction from list and calls handler with provided error. Can return ErrTransactionNotExists and ErrAgentClosed.

type AlternateServer added in v0.3.0

type AlternateServer struct {
	IP   net.IP
	Port int
}

AlternateServer represents ALTERNATE-SERVER attribute.

RFC 5389 Section 15.11

func (*AlternateServer) AddTo added in v0.3.0

func (s *AlternateServer) AddTo(m *Message) error

AddTo adds ALTERNATE-SERVER attribute to message.

func (*AlternateServer) GetFrom added in v0.3.0

func (s *AlternateServer) GetFrom(m *Message) error

GetFrom decodes ALTERNATE-SERVER from message.

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 (
	AttrOtherAddress  AttrType = 0x802C // OTHER-ADDRESS
	AttrChangeRequest AttrType = 0x0003 // CHANGE-REQUEST
)

Attributes from RFC 5780 NAT Behavior Discovery

const (
	AttrConnectionID AttrType = 0x002a // CONNECTION-ID
)

Attributes from RFC 6062 TURN Extensions for TCP Allocations.

const (
	AttrOrigin AttrType = 0x802F
)

Attributes from An Origin Attribute for the STUN Protocol.

const (
	AttrRequestedAddressFamily AttrType = 0x0017 // REQUESTED-ADDRESS-FAMILY
)

Attributes from RFC 6156 TURN IPv6.

func (AttrType) Optional added in v0.3.0

func (t AttrType) Optional() bool

Optional returns true if type is from comprehension-optional range (0x8000-0xFFFF).

func (AttrType) Required added in v0.3.0

func (t AttrType) Required() bool

Required returns true if type is from comprehension-required range (0x0000-0x7FFF).

func (AttrType) String

func (t AttrType) String() string

func (AttrType) Value added in v0.3.0

func (t AttrType) Value() uint16

Value returns uint16 representation of attribute type.

type Attributes added in v0.3.0

type Attributes []RawAttribute

Attributes is list of message attributes.

func (Attributes) Get added in v0.3.0

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 Checker added in v0.3.0

type Checker interface {
	Check(m *Message) error
}

Checker checks *Message attribute.

type Client

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

Client simulates "connection" to STUN server.

func Dial added in v0.3.0

func Dial(network, address string) (*Client, error)

Dial connects to the address on the named network and then initializes Client on that connection, returning error if any.

func NewClient

func NewClient(conn Connection, options ...ClientOption) (*Client, error)

NewClient initializes new Client from provided options, starting internal goroutines and using default options fields if necessary. Call Close method after using Client to close conn and release resources.

The conn will be closed on Close call. Use WithNoConnClose option to prevent that.

Note that user should handle the protocol multiplexing, client does not provide any API for it, so if you need to read application data, wrap the connection with your (de-)multiplexer and pass the wrapper as conn.

func (*Client) Close

func (c *Client) Close() error

Close stops internal connection and agent, returning CloseErr on error.

func (*Client) Do added in v0.3.0

func (c *Client) Do(m *Message, f func(Event)) error

Do is Start wrapper that waits until callback is called. If no callback provided, Indicate is called instead.

Do has cpu overhead due to blocking, see BenchmarkClient_Do. Use Start method for less overhead.

func (*Client) Indicate added in v0.3.0

func (c *Client) Indicate(m *Message) error

Indicate sends indication m to server. Shorthand to Start call with zero deadline and callback.

func (*Client) SetRTO added in v0.3.0

func (c *Client) SetRTO(rto time.Duration)

SetRTO sets current RTO value.

func (*Client) Start added in v0.3.0

func (c *Client) Start(m *Message, h Handler) error

Start starts transaction (if h set) and writes message to server, handler is called asynchronously.

type ClientAgent added in v0.3.0

type ClientAgent interface {
	Process(*Message) error
	Close() error
	Start(id [TransactionIDSize]byte, deadline time.Time) error
	Stop(id [TransactionIDSize]byte) error
	Collect(time.Time) error
	SetHandler(h Handler) error
}

ClientAgent is Agent implementation that is used by Client to process transactions.

type ClientOption added in v0.3.0

type ClientOption func(c *Client)

ClientOption sets some client option.

var WithNoConnClose ClientOption = func(c *Client) {
	c.closeConn = false
}

WithNoConnClose prevents client from closing underlying connection when the Close() method is called.

func WithAgent added in v0.3.0

func WithAgent(a ClientAgent) ClientOption

WithAgent sets client STUN agent.

Defaults to agent implementation in current package, see agent.go.

func WithClock added in v0.3.0

func WithClock(clock Clock) ClientOption

WithClock sets Clock of client, the source of current time. Also clock is passed to default collector if set.

func WithCollector added in v0.3.0

func WithCollector(coll Collector) ClientOption

WithCollector rests client timeout collector, the implementation of ticker which calls function on each tick.

func WithHandler added in v0.3.0

func WithHandler(h Handler) ClientOption

WithHandler sets client handler which is called if Agent emits the Event with TransactionID that is not currently registered by Client. Useful for handling Data indications from TURN server.

func WithRTO added in v0.3.0

func WithRTO(rto time.Duration) ClientOption

WithRTO sets client RTO as defined in STUN RFC.

func WithTimeoutRate added in v0.3.0

func WithTimeoutRate(d time.Duration) ClientOption

WithTimeoutRate sets RTO timer minimum resolution.

type Clock added in v0.3.0

type Clock interface {
	Now() time.Time
}

Clock abstracts the source of current time.

type CloseErr added in v0.3.0

type CloseErr struct {
	AgentErr      error
	ConnectionErr error
}

CloseErr indicates client close failure.

func (CloseErr) Error added in v0.3.0

func (c CloseErr) Error() string

type Collector added in v0.3.0

type Collector interface {
	Start(rate time.Duration, f func(now time.Time)) error
	Close() error
}

Collector calls function f with constant rate.

The simple Collector is ticker which calls function on each tick.

type Connection added in v0.3.0

type Connection interface {
	io.Reader
	io.Writer
	io.Closer
}

Connection wraps Reader, Writer and Closer interfaces.

type DecodeErr added in v0.3.0

type DecodeErr struct {
	Place   DecodeErrPlace
	Message string
}

DecodeErr records an error and place when it is occurred.

func (DecodeErr) Error added in v0.3.0

func (e DecodeErr) Error() string

func (DecodeErr) IsInvalidCookie added in v0.3.0

func (e DecodeErr) IsInvalidCookie() bool

IsInvalidCookie returns true if error means that magic cookie value is invalid.

func (DecodeErr) IsPlace added in v0.3.0

func (e DecodeErr) IsPlace(p DecodeErrPlace) bool

IsPlace reports if error place is p.

func (DecodeErr) IsPlaceChildren added in v0.3.0

func (e DecodeErr) IsPlaceChildren(c string) bool

IsPlaceChildren reports if error place children is c.

func (DecodeErr) IsPlaceParent added in v0.3.0

func (e DecodeErr) IsPlaceParent(p string) bool

IsPlaceParent reports if error place parent is p.

type DecodeErrPlace added in v0.3.0

type DecodeErrPlace struct {
	Parent   string
	Children string
}

DecodeErrPlace records a place where error is occurred.

func (DecodeErrPlace) String added in v0.3.0

func (p DecodeErrPlace) String() string

type ErrorCode

type ErrorCode int

ErrorCode is code for ERROR-CODE attribute.

const (
	CodeTryAlternate     ErrorCode = 300
	CodeBadRequest       ErrorCode = 400
	CodeUnauthorized     ErrorCode = 401
	CodeUnknownAttribute ErrorCode = 420
	CodeStaleNonce       ErrorCode = 438
	CodeRoleConflict     ErrorCode = 487
	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.

RFC 5766 Section 15

const (
	CodeConnAlreadyExists    ErrorCode = 446
	CodeConnTimeoutOrFailure ErrorCode = 447
)

Error codes from RFC 6062.

RFC 6062 Section 6.3

const (
	CodeAddrFamilyNotSupported ErrorCode = 440 // Address Family not Supported
	CodePeerAddrFamilyMismatch ErrorCode = 443 // Peer Address Family Mismatch
)

Error codes from RFC 6156.

RFC 6156 Section 10.2

func (ErrorCode) AddTo added in v0.3.0

func (c ErrorCode) AddTo(m *Message) error

AddTo adds ERROR-CODE with default reason to m. If there is no default reason, returns ErrNoDefaultReason.

type ErrorCodeAttribute added in v0.3.0

type ErrorCodeAttribute struct {
	Code   ErrorCode
	Reason []byte
}

ErrorCodeAttribute represents ERROR-CODE attribute.

RFC 5389 Section 15.6

func (ErrorCodeAttribute) AddTo added in v0.3.0

func (c ErrorCodeAttribute) AddTo(m *Message) error

AddTo adds ERROR-CODE to m.

func (*ErrorCodeAttribute) GetFrom added in v0.3.0

func (c *ErrorCodeAttribute) GetFrom(m *Message) error

GetFrom decodes ERROR-CODE from m. Reason is valid until m.Raw is valid.

func (ErrorCodeAttribute) String added in v0.3.0

func (c ErrorCodeAttribute) String() string

type Event added in v0.3.0

type Event struct {
	TransactionID [TransactionIDSize]byte
	Message       *Message
	Error         error
}

Event is passed to Handler describing the transaction event. Do not reuse outside Handler.

type FingerprintAttr added in v0.3.0

type FingerprintAttr struct{}

FingerprintAttr represents FINGERPRINT attribute.

RFC 5389 Section 15.5

var Fingerprint FingerprintAttr

Fingerprint is shorthand for FingerprintAttr.

Example:

m := New()
Fingerprint.AddTo(m)

func (FingerprintAttr) AddTo added in v0.3.0

func (FingerprintAttr) AddTo(m *Message) error

AddTo adds fingerprint to message.

func (FingerprintAttr) Check added in v0.3.0

func (FingerprintAttr) Check(m *Message) error

Check reads fingerprint value from m and checks it, returning error if any. Can return *AttrLengthErr, ErrAttributeNotFound, and *CRCMismatch.

type Getter added in v0.3.0

type Getter interface {
	GetFrom(m *Message) error
}

Getter parses attribute from *Message.

type Handler added in v0.3.0

type Handler func(e Event)

Handler handles state changes of transaction.

Handler is called on transaction state change. Usage of e is valid only during call, user must copy needed fields explicitly.

var NoopHandler Handler = func(e Event) {}

NoopHandler just discards any event.

type MappedAddress added in v0.3.0

type MappedAddress struct {
	IP   net.IP
	Port int
}

MappedAddress represents MAPPED-ADDRESS attribute.

This attribute is used only by servers for achieving backwards compatibility with RFC 3489 clients.

RFC 5389 Section 15.1

func (*MappedAddress) AddTo added in v0.3.0

func (a *MappedAddress) AddTo(m *Message) error

AddTo adds MAPPED-ADDRESS to message.

func (*MappedAddress) GetFrom added in v0.3.0

func (a *MappedAddress) GetFrom(m *Message) error

GetFrom decodes MAPPED-ADDRESS from message.

func (MappedAddress) String added in v0.3.0

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
// to reduce allocations.
// 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
if Fingerprint.Check(decoded) == nil {
	fmt.Println("fingerprint: ok")
} else {
	fmt.Println("fingerprint: 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: failed

func Build

func Build(setters ...Setter) (*Message, error)

Build wraps Message.Build method.

func MustBuild added in v0.3.0

func MustBuild(setters ...Setter) *Message

MustBuild wraps Build call and panics on error.

func New added in v0.3.0

func New() *Message

New returns *Message with pre-allocated Raw.

func (*Message) Add added in v0.3.0

func (m *Message) Add(t AttrType, v []byte)

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) AddTo added in v0.3.0

func (m *Message) AddTo(b *Message) error

AddTo sets b.TransactionID to m.TransactionID.

Implements Setter to aid in crafting responses.

func (*Message) Build added in v0.3.0

func (m *Message) Build(setters ...Setter) error

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) Check added in v0.3.0

func (m *Message) Check(checkers ...Checker) error

Check applies checkers to message in batch, returning on first error.

func (*Message) CloneTo added in v0.3.0

func (m *Message) CloneTo(b *Message) error

CloneTo clones m to b securing any further m mutations.

func (*Message) Contains added in v0.3.0

func (m *Message) Contains(t AttrType) bool

Contains return true if message contain t attribute.

func (*Message) Decode added in v0.3.0

func (m *Message) Decode() error

Decode decodes m.Raw into m.

func (*Message) Encode added in v0.3.0

func (m *Message) Encode()

Encode re-encodes message into m.Raw.

func (*Message) Equal added in v0.3.0

func (m *Message) Equal(b *Message) bool

Equal returns true if Message b equals to m. Ignores m.Raw.

func (*Message) ForEach added in v0.3.0

func (m *Message) ForEach(t AttrType, f func(m *Message) error) error

ForEach is helper that iterates over message attributes allowing to call Getter in f callback to get all attributes of type t and returning on first f error.

The m.Get method inside f will be returning next attribute on each f call. Does not error if there are no results.

Example
m := MustBuild(NewRealm("realm1"), NewRealm("realm2"))
if err := m.ForEach(AttrRealm, func(m *Message) error {
	var r Realm
	if err := r.GetFrom(m); err != nil {
		return err
	}
	fmt.Println(r)
	return nil
}); err != nil {
	fmt.Println("error:", err)
}
Output:

realm1
realm2

func (*Message) Get added in v0.3.0

func (m *Message) Get(t AttrType) ([]byte, error)

Get returns byte slice that represents attribute value, if there is no attribute with such type, ErrAttributeNotFound is returned.

func (*Message) NewTransactionID added in v0.3.0

func (m *Message) NewTransactionID() error

NewTransactionID sets m.TransactionID to random value from crypto/rand and returns error if any.

func (*Message) Parse added in v0.3.0

func (m *Message) Parse(getters ...Getter) error

Parse applies getters to message in batch, returning on first error.

func (*Message) ReadFrom added in v0.3.0

func (m *Message) ReadFrom(r io.Reader) (int64, error)

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 added in v0.3.0

func (m *Message) Reset()

Reset resets Message, attributes and underlying buffer length.

func (*Message) SetType added in v0.3.0

func (m *Message) SetType(t MessageType)

SetType sets m.Type and writes it to m.Raw.

func (*Message) String added in v0.3.0

func (m *Message) String() string

func (*Message) Write added in v0.3.0

func (m *Message) Write(tBuf []byte) (int, error)

Write decodes message and return error if any.

Any error is unrecoverable, but message could be partially decoded.

func (*Message) WriteAttributes added in v0.3.0

func (m *Message) WriteAttributes()

WriteAttributes encodes all m.Attributes to m.

func (*Message) WriteHeader added in v0.3.0

func (m *Message) WriteHeader()

WriteHeader writes header to underlying buffer. Not goroutine-safe.

func (*Message) WriteLength added in v0.3.0

func (m *Message) WriteLength()

WriteLength writes m.Length to m.Raw.

func (*Message) WriteTo added in v0.3.0

func (m *Message) WriteTo(w io.Writer) (int64, error)

WriteTo implements WriterTo via calling Write(m.Raw) on w and returning call result.

func (*Message) WriteTransactionID added in v0.3.0

func (m *Message) WriteTransactionID()

WriteTransactionID writes m.TransactionID to m.Raw.

func (*Message) WriteType added in v0.3.0

func (m *Message) WriteType()

WriteType writes m.Type 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 Check methods are using zero-allocation version of hmac, see newHMAC function and internal/hmac/pool.go.

RFC 5389 Section 15.4

func NewLongTermIntegrity added in v0.3.0

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 added in v0.3.0

func NewShortTermIntegrity(password string) MessageIntegrity

NewShortTermIntegrity returns new MessageIntegrity with key for short-term credentials. Password must be SASL-prepared.

func (MessageIntegrity) AddTo added in v0.3.0

func (i MessageIntegrity) AddTo(m *Message) error

AddTo adds MESSAGE-INTEGRITY attribute to message.

CPU costly, see BenchmarkMessageIntegrity_AddTo.

func (MessageIntegrity) Check added in v0.3.0

func (i MessageIntegrity) Check(m *Message) error

Check checks MESSAGE-INTEGRITY attribute.

CPU costly, see BenchmarkMessageIntegrity_Check.

func (MessageIntegrity) String added in v0.3.0

func (i MessageIntegrity) String() string

type MessageType added in v0.3.0

type MessageType struct {
	Method Method       // e.g. binding
	Class  MessageClass // e.g. request
}

MessageType is STUN Message Type Field.

func NewType added in v0.3.0

func NewType(method Method, class MessageClass) MessageType

NewType returns new message type with provided method and class.

func (MessageType) AddTo added in v0.3.0

func (t MessageType) AddTo(m *Message) error

AddTo sets m type to t.

func (*MessageType) ReadValue added in v0.3.0

func (t *MessageType) ReadValue(v uint16)

ReadValue decodes uint16 into MessageType.

func (MessageType) String added in v0.3.0

func (t MessageType) String() string

func (MessageType) Value added in v0.3.0

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.

const (
	MethodBinding          Method = 0x001
	MethodAllocate         Method = 0x003
	MethodRefresh          Method = 0x004
	MethodSend             Method = 0x006
	MethodData             Method = 0x007
	MethodCreatePermission Method = 0x008
	MethodChannelBind      Method = 0x009
)

Possible methods for STUN Message.

const (
	MethodConnect           Method = 0x000a
	MethodConnectionBind    Method = 0x000b
	MethodConnectionAttempt Method = 0x000c
)

Methods from RFC 6062.

func (Method) String

func (m Method) String() string

type Nonce

type Nonce []byte

Nonce represents NONCE attribute.

RFC 5389 Section 15.8

func NewNonce added in v0.3.0

func NewNonce(nonce string) Nonce

NewNonce returns new Nonce from string.

func (Nonce) AddTo added in v0.3.0

func (n Nonce) AddTo(m *Message) error

AddTo adds NONCE to message.

func (*Nonce) GetFrom added in v0.3.0

func (n *Nonce) GetFrom(m *Message) error

GetFrom gets NONCE from message.

func (Nonce) String added in v0.3.0

func (n Nonce) String() string

type OtherAddress added in v0.3.4

type OtherAddress struct {
	IP   net.IP
	Port int
}

OtherAddress represents OTHER-ADDRESS attribute.

RFC 5780 Section 7.4

func (*OtherAddress) AddTo added in v0.3.4

func (o *OtherAddress) AddTo(m *Message) error

AddTo adds OTHER-ADDRESS attribute to message.

func (*OtherAddress) GetFrom added in v0.3.4

func (o *OtherAddress) GetFrom(m *Message) error

GetFrom decodes OTHER-ADDRESS from message.

func (OtherAddress) String added in v0.3.4

func (o OtherAddress) String() string

type RawAttribute

type RawAttribute struct {
	Type   AttrType
	Length uint16 // ignored while encoding
	Value  []byte
}

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) AddTo added in v0.3.0

func (a RawAttribute) AddTo(m *Message) error

AddTo implements Setter, adding attribute as a.Type with a.Value and ignoring the Length field.

func (RawAttribute) Equal added in v0.3.0

func (a RawAttribute) Equal(b RawAttribute) bool

Equal returns true if a == b.

func (RawAttribute) String added in v0.3.0

func (a RawAttribute) String() string

type Realm

type Realm []byte

Realm represents REALM attribute.

RFC 5389 Section 15.7

func NewRealm added in v0.3.0

func NewRealm(realm string) Realm

NewRealm returns Realm with provided value. Must be SASL-prepared.

func (Realm) AddTo added in v0.3.0

func (n Realm) AddTo(m *Message) error

AddTo adds NONCE to message.

func (*Realm) GetFrom added in v0.3.0

func (n *Realm) GetFrom(m *Message) error

GetFrom gets REALM from message.

func (Realm) String added in v0.3.0

func (n Realm) String() string

type Setter added in v0.3.0

type Setter interface {
	AddTo(m *Message) error
}

Setter sets *Message attribute.

var TransactionID Setter = transactionIDSetter{}

TransactionID is Setter for m.TransactionID.

func NewTransactionIDSetter added in v0.3.0

func NewTransactionIDSetter(value [TransactionIDSize]byte) Setter

NewTransactionIDSetter returns new Setter that sets message transaction id to provided value.

type Software

type Software []byte

Software is SOFTWARE attribute.

RFC 5389 Section 15.10

func NewSoftware added in v0.3.0

func NewSoftware(software string) Software

NewSoftware returns *Software from string.

func (Software) AddTo added in v0.3.0

func (s Software) AddTo(m *Message) error

AddTo adds Software attribute to m.

func (*Software) GetFrom added in v0.3.0

func (s *Software) GetFrom(m *Message) error

GetFrom decodes Software from m.

func (Software) String added in v0.3.0

func (s Software) String() string

type StopErr added in v0.3.0

type StopErr struct {
	Err   error // value returned by Stop()
	Cause error // error that caused Stop() call
}

StopErr occurs when Client fails to stop transaction while processing error.

func (StopErr) Error added in v0.3.0

func (e StopErr) Error() string

type TextAttribute added in v0.3.0

type TextAttribute []byte

TextAttribute is helper for adding and getting text attributes.

func (TextAttribute) AddToAs added in v0.3.0

func (v TextAttribute) AddToAs(m *Message, t AttrType, maxLen int) error

AddToAs adds attribute with type t to m, checking maximum length. If maxLen is less than 0, no check is performed.

func (*TextAttribute) GetFromAs added in v0.3.0

func (v *TextAttribute) GetFromAs(m *Message, t AttrType) error

GetFromAs gets t attribute from m and appends its value to reseted v.

type UnknownAttributes

type UnknownAttributes []AttrType

UnknownAttributes represents UNKNOWN-ATTRIBUTES attribute.

RFC 5389 Section 15.9

func (UnknownAttributes) AddTo added in v0.3.0

func (a UnknownAttributes) AddTo(m *Message) error

AddTo adds UNKNOWN-ATTRIBUTES attribute to message.

func (*UnknownAttributes) GetFrom added in v0.3.0

func (a *UnknownAttributes) GetFrom(m *Message) error

GetFrom parses UNKNOWN-ATTRIBUTES from message.

func (UnknownAttributes) String added in v0.3.0

func (a UnknownAttributes) String() string

type Username

type Username []byte

Username represents USERNAME attribute.

RFC 5389 Section 15.3

func NewUsername added in v0.3.0

func NewUsername(username string) Username

NewUsername returns Username with provided value.

func (Username) AddTo added in v0.3.0

func (u Username) AddTo(m *Message) error

AddTo adds USERNAME attribute to message.

func (*Username) GetFrom added in v0.3.0

func (u *Username) GetFrom(m *Message) error

GetFrom gets USERNAME from message.

func (Username) String added in v0.3.0

func (u Username) String() string

type XORMappedAddress added in v0.3.0

type XORMappedAddress struct {
	IP   net.IP
	Port int
}

XORMappedAddress implements XOR-MAPPED-ADDRESS attribute.

RFC 5389 Section 15.2

func (XORMappedAddress) AddTo added in v0.3.0

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 added in v0.3.0

func (a XORMappedAddress) AddToAs(m *Message, t AttrType) error

AddToAs adds XOR-MAPPED-ADDRESS value to m as t attribute.

func (*XORMappedAddress) GetFrom added in v0.3.0

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 added in v0.3.0

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 added in v0.3.0

func (a XORMappedAddress) String() string

Directories

Path Synopsis
cmd
stun-multiplex
Command stun-multiplex is example of doing UDP connection multiplexing that splits incoming UDP packets to two streams, "STUN Data" and "Application Data".
Command stun-multiplex is example of doing UDP connection multiplexing that splits incoming UDP packets to two streams, "STUN Data" and "Application Data".
internal
hmac
Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198.
Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL