stun

package module
v0.0.0-...-591cc1a Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

stun

STUN is a library that allows for complete control over the STUN protocol and some of its ICE-specific extensions. It can be used to build custom STUN clients and servers, as well as to implement binding checks for services such as WebRTC and QUIC.

A client, server and binding agent implementations are provided in this package, but that should not discourage from using the underlying primitives to build personalized solutions.

Both IPv4 and IPv6 are fully supported, as well as UDP, TCP and TLS protocols.

This package is the base for further work I am doing around STUN and related protocols. I am releasing it as open source so others can reuse the same building blocks and/or contribute to it.

Installation

go get github.com/riraccuia/stun

Examples

Querying a STUN server

There are several ways to query a STUN server, the first is to use one of the convenience functions: QueryServerUDP, QueryServerTCP, QueryServerTLS.

randomPort := rand.Intn(65535-1024) + 1024
result, err := stun.QueryServerUDP("stun.example.com:3478", &net.UDPAddr{IP: nil, Port: randomPort})

if err != nil {
    // handle error
}

fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)


result, err = stun.QueryServerTCP("stun.example.com:3478", &net.TCPAddr{IP: nil, Port: 0})

if err != nil {
	// handle error
}

fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)

A generic QueryServer method is also available on Client and can be used to query a STUN server over any supported protocol. Optional logging uses WithLoggerFunc:

logger := func(level string, args ...any) {
	// plug into your logger; level is informational for the client
	_ = level
	_ = args
}
client := stun.NewClient("stun.example.com:3478").WithLoggerFunc(logger)
randomPort := rand.Intn(65535-1024) + 1024
result, err := client.QueryServer("stun.example.com:3478", randomPort, "tcp", nil)

if err != nil {
	// handle error
}

fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)
Build your own STUN client
// connect to the STUN server using the chosen protocol
conn, err := net.Dial("tcp", "stun.example.com:3478")
if err != nil {
	// handle error
}
defer conn.Close()
// build the request
req, err := stun.BuildBindingRequest(nil)
if err != nil {
	// handle error
}
// send the request to the connection
_, err = req.WriteTo(conn)
if err != nil {
	// handle error
}
// receive the response
hdr := make([]byte, 20)
if _, err = io.ReadFull(conn, hdr); err != nil {
	// handle error
}
bodyLen := int(binary.BigEndian.Uint16(hdr[2:4]))
body := make([]byte, bodyLen)
if _, err = io.ReadFull(conn, body); err != nil {
	// handle error
}
raw := append(hdr, body...)
msg, err := stun.DecodeMessage(raw)
if err != nil {
	// handle error
}
result, err := stun.ProcessBindingResponse(msg, req.Header.TransactionID, nil)
if err != nil {
	// handle error
}
fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)

Implemented RFCs

  • RFC 3489 - Session Traversal Utilities for NAT (STUN)
  • RFC 5389 - Session Traversal Utilities for NAT (STUN)
  • RFC 8489 - Session Traversal Utilities for NAT (STUN)
  • RFC 8445 - Interactive Connectivity Establishment (ICE) (only STUN extensions are implemented)
  • RFC 8265 - Preparation, Enforcement, and Comparison of Internationalized Strings Representing Usernames and Passwords (only OpaqueString profile is implemented)

Documentation

Overview

STUN is a library that allows for complete control over the STUN protocol and some of its ICE-specific extensions. It can be used to build custom STUN clients and servers, as well as to implement binding checks for services such as WebRTC and QUIC.

A client, server and binding agent implementations are provided in this package, but that should not discourage from using the underlying primitives to build personalized solutions.

Both IPv4 and IPv6 are fully supported, as well as UDP, TCP and TLS protocols.

Examples

Querying a STUN server

There are several ways to query a STUN server, the first is to use one of the convenience functions: QueryServerUDP, QueryServerTCP, QueryServerTLS.

randomPort := rand.Intn(65535-1024) + 1024
result, err := stun.QueryServerUDP("stun.example.com:3478", &net.UDPAddr{IP: nil, Port: randomPort})

if err != nil {
    // handle error
}

fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)

result, err = stun.QueryServerTCP("stun.example.com:3478", &net.TCPAddr{IP: nil, Port: 0})

if err != nil {
	// handle error
}

fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)

A generic QueryServer method on Client can be used to query a STUN server over any supported protocol. Optional logging uses WithLoggerFunc.

logger := func(level string, args ...any) {
	// plug into your logger; level is informational for the client
	_ = level
	_ = args
}
client := stun.NewClient("stun.example.com:3478").WithLoggerFunc(logger)
randomPort := rand.Intn(65535-1024) + 1024
result, err := client.QueryServer("stun.example.com:3478", randomPort, "tcp", nil)

if err != nil {
	// handle error
}

fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)

Build your own STUN client

// connect to the STUN server using the chosen protocol
conn, err := net.Dial("tcp", "stun.example.com:3478")
if err != nil {
	// handle error
}
defer conn.Close()
// build the request
req, err := stun.BuildBindingRequest(nil)
if err != nil {
	// handle error
}
// send the request to the connection
_, err = req.WriteTo(conn)
if err != nil {
	// handle error
}
// receive the response
hdr := make([]byte, 20)
if _, err = io.ReadFull(conn, hdr); err != nil {
	// handle error
}
bodyLen := int(binary.BigEndian.Uint16(hdr[2:4]))
body := make([]byte, bodyLen)
if _, err = io.ReadFull(conn, body); err != nil {
	// handle error
}
raw := append(hdr, body...)
msg, err := stun.DecodeMessage(raw)
if err != nil {
	// handle error
}
result, err := stun.ProcessBindingResponse(msg, req.Header.TransactionID, nil)
if err != nil {
	// handle error
}
fmt.Printf("STUN server returned mapped <ip:port>: %s:%d\n", result.IP, result.Port)

Implemented RFCs:

  • RFC 3489 - Session Traversal Utilities for NAT (STUN)
  • RFC 5389 - Session Traversal Utilities for NAT (STUN)
  • RFC 8489 - Session Traversal Utilities for NAT (STUN)
  • RFC 8445 - Interactive Connectivity Establishment (ICE) (only STUN extensions are implemented)
  • RFC 8265 - Preparation, Enforcement, and Comparison of Internationalized Strings Representing Usernames and Passwords (only OpaqueString profile is implemented)

Index

Constants

View Source
const (

	// Comprehension-required range (0x0000-0x7FFF)
	AttrUsername               uint16 = 0x0006
	AttrMessageIntegrity       uint16 = 0x0008
	AttrMessageIntegritySHA256 uint16 = 0x001C
	AttrErrorCode              uint16 = 0x0009
	AttrRealm                  uint16 = 0x0014
	AttrNonce                  uint16 = 0x0015
	AttrXorMappedAddress       uint16 = 0x0020
	// Comprehension-optional range (0x8000-0xFFFF)
	AttrFingerprint uint16 = 0x8028

	TLVPrefixLength = 4
)
View Source
const (
	AttrICEPriority     uint16 = 0x0024
	AttrICEUseCandidate uint16 = 0x0025
	AttrICEControlled   uint16 = 0x8029
	AttrICEControlling  uint16 = 0x802A
)
View Source
const (

	// STUN message types
	MsgTypeBindingRequest       uint16 = 0x0001
	MsgTypeBindingResponse      uint16 = 0x0101
	MsgTypeBindingErrorResponse uint16 = 0x0111
	// FINGERPRINT XOR value (RFC 5389 Section 15.5)
	FingerprintXorValue uint32 = 0x5354554e

	// STUN magic cookie value
	MagicCookie uint32 = 0x2112A442
)

Variables

View Source
var ErrParseMessage = errors.New("failed to parse STUN message")
View Source
var StunClassStrings = map[Class]string{
	ClassRequest:         "request",
	ClassIndication:      "indication",
	ClassSuccessResponse: "success response",
	ClassErrorResponse:   "error response",
}
View Source
var StunMethodStrings = map[Method]string{
	MethodBinding: "binding",
}

Functions

func CalculateFingerprint

func CalculateFingerprint(message []byte) uint32

CalculateFingerprint calculates the FINGERPRINT attribute value for a STUN message. The input should be the entire message up to (but excluding) the FINGERPRINT attribute itself. Per RFC 5389, the CRC covers the message with the header Length field including the FINGERPRINT attribute (8 bytes), so we adjust the Length before hashing and restore it afterwards.

func CalculateShortTermMessageIntegrity

func CalculateShortTermMessageIntegrity(message []byte, password string) []byte

CalculateShortTermMessageIntegrity calculates the HMAC-SHA1 message integrity according to RFC 8489 Section 14.5 (MESSAGE-INTEGRITY). The given password is processed using the OpaqueString profile. Returns 20 bytes.

func CalculateShortTermMessageIntegritySHA256

func CalculateShortTermMessageIntegritySHA256(message []byte, password string) []byte

CalculateShortTermMessageIntegritySHA256 calculates the HMAC-SHA256 message integrity according to RFC 8489 Section 14.6 (MESSAGE-INTEGRITY-SHA256). The given password is processed using the OpaqueString profile. Returns 32 bytes.

func CalculateShortTermMessageIntegrityWithHash

func CalculateShortTermMessageIntegrityWithHash(message []byte, password string, attrType uint16, newHash func() hash.Hash) []byte

CalculateShortTermMessageIntegrityWithHash computes HMAC-based message integrity for STUN per RFC 8489. It searches for attrType in the message, truncates at that position, and computes HMAC using OpaqueString(password) as the key. newHash supplies the hash algorithm; its Size() determines the attribute value length. This method could be used to implement new message integrity algorithms, other than the currenly supported ones by the spec (HMAC-SHA1 and HMAC-SHA256).

func CreateXorMappedAddress

func CreateXorMappedAddress(addr net.Addr, txID [12]byte) ([]byte, error)

CreateXorMappedAddress creates a full, raw XOR-MAPPED-ADDRESS attribute for the given address and transaction ID.

func EncodeMessageType

func EncodeMessageType(method Method, class Class) uint16

EncodeMessageType encodes a STUN method and class into the wire value. The masks and shifts intentionally mirror RFC 8489 Appendix A.

func IsErrorResponseType

func IsErrorResponseType(msgType uint16) bool

IsErrorResponseType reports whether the raw STUN message type is an error response.

func IsIndicationType

func IsIndicationType(msgType uint16) bool

IsIndicationType reports whether the raw STUN message type is an indication.

func IsRequestType

func IsRequestType(msgType uint16) bool

IsRequestType reports whether the raw STUN message type is a request.

func IsSuccessResponseType

func IsSuccessResponseType(msgType uint16) bool

IsSuccessResponseType reports whether the raw STUN message type is a success response.

func OpaqueString

func OpaqueString(s string) string

OpaqueString converts a string to an OpaqueString according to RFC 8265. RFC 8489 mandates the use of the OpaqueString profile for the HMAC-SHA1 key calculation and also the USERNAME, USERHASH and REALM attributes. The OpaqueString profile is defined in RFC 8265 section 4.2. The encoding used is UTF-8 (RFC 3629).

func SendErrorResponse

func SendErrorResponse(conn net.Conn, transactionID [12]byte, code int, reason string, auth *AuthConfig) error

SendErrorResponse creates and sends a STUN error response with the given error code and reason. If auth is provided, it will add authentication attributes.

func ValidateMethodAndClass

func ValidateMethodAndClass(msgType uint16, expectedMethod Method, allowedClasses ...Class) error

ValidateMethodAndClass validates that a raw STUN message type matches the expected method and one of the allowed classes.

func ValidateShortTermIntegrity

func ValidateShortTermIntegrity(request *Message, expected *AuthConfig) error

ValidateShortTermIntegrity validates a Binding request against expected short-term credentials per RFC 8489 Section 9.1. It compares the USERNAME (after OpaqueString processing) and verifies MESSAGE-INTEGRITY using the expected password. Returns nil if validation passes. When expected is nil or expected.Password is empty, returns nil (no auth required). Callers are responsible for sending 401 on error.

Types

type Attribute

type Attribute interface {
	Serializable
	// DecodeFromBytes decodes the input bytes into the attribute.
	DecodeFromBytes(b []byte) error
	// GetType returns the type of the attribute.
	GetType() uint16
	// IsICE reports whether the attribute is an ICE extension attribute.
	IsICE() bool
}

Attribute is the generalized interface for all STUN attributes.

func DecodeAttributes

func DecodeAttributes(data []byte) ([]Attribute, error)

DecodeAttributes decodes the input bytes as raw attribute data into a slice of Attribute. This is assumed to be the raw attribute data, not the entire message.

type AuthConfig

type AuthConfig struct {
	Username string
	Password string
	Realm    string
	Nonce    string
}

AuthConfig represents generic STUN authentication configuration.

type BindingAgent

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

func NewBindingAgent

func NewBindingAgent(config *BindingAgentConfig) *BindingAgent

func (*BindingAgent) HandleRequest

func (b *BindingAgent) HandleRequest(request *Message) error

HandleRequest handles an incoming STUN binding request and sends a response

func (*BindingAgent) HandleResponse

func (b *BindingAgent) HandleResponse(response *Message, transactionID [12]byte) (*BindingResult, error)

HandleResponse parses a STUN response and returns the binding result.

func (*BindingAgent) ICENominateCandidate

func (b *BindingAgent) ICENominateCandidate() (*BindingResult, error)

ICENominateCandidate sets the ICE nominated flag to true, then calls BindingAgent.SendRequest to tell the other side that we are going to use this candidate. It returns the binding result.

func (*BindingAgent) ICENominated

func (b *BindingAgent) ICENominated() bool

ICENominated returns true if the binding agent is nominated for ICE usage by the remote peer.

func (*BindingAgent) ICEPriority

func (b *BindingAgent) ICEPriority() uint32

ICEPriority returns the ICE priority of the binding agent.

func (*BindingAgent) Receive

func (b *BindingAgent) Receive()

Receive starts receiving binding requests from the wrapped connection. Call SetConn first to set the connection.

func (*BindingAgent) SendRequest

func (b *BindingAgent) SendRequest(waitForResponse bool) (result *BindingResult, err error)

SendRequest sends a STUN binding request and returns the mapped address

func (*BindingAgent) SetConfig

func (b *BindingAgent) SetConfig(config *BindingAgentConfig)

func (*BindingAgent) SetConn

func (b *BindingAgent) SetConn(conn net.Conn)

SetConn sets the connection to receive or send binding requests to.

func (*BindingAgent) StopReceive

func (b *BindingAgent) StopReceive()

type BindingAgentConfig

type BindingAgentConfig struct {
	// Logger receives agent log events. When nil, a no-op logger is installed.
	Logger LoggerFunc
	// RequestOptions are applied when this agent builds and sends an outgoing
	// Binding request. It may be left nil to send a plain STUN Binding request
	// with the default fingerprint handling.
	RequestOptions *BindingOptions
	// HandleOptions are applied when this agent receives an incoming Binding
	// request, validates it, and builds the corresponding Binding response. It
	// may be left nil to accept plain Binding requests with the default
	// fingerprint requirement.
	HandleOptions *BindingOptions
}

func NewBindingAgentConfig

func NewBindingAgentConfig(logger LoggerFunc, auth *AuthConfig) *BindingAgentConfig

NewBindingAgentConfig builds a BindingAgentConfig for generic STUN short-term credentials (RFC 8489 Section 9.1). Passing nil auth disables request/response auth.

func NewControlledICEBindingAgentConfig

func NewControlledICEBindingAgentConfig(logger LoggerFunc, auth *IceAuth, priority uint32) *BindingAgentConfig

NewControlledICEBindingAgentConfig builds the ICE-specific BindingAgentConfig for the controlled side of an ICE connectivity check.

func NewControllingICEBindingAgentConfig

func NewControllingICEBindingAgentConfig(logger LoggerFunc, auth *IceAuth, priority uint32) *BindingAgentConfig

NewControllingICEBindingAgentConfig builds the ICE-specific BindingAgentConfig for the controlling side of an ICE connectivity check.

func NewICEBindingAgentConfig

func NewICEBindingAgentConfig(logger LoggerFunc, iceAuth *IceAuth, attributes *IceConfig) *BindingAgentConfig

NewICEBindingAgentConfig builds a BindingAgentConfig that enables ICE usage. Passing nil auth or attributes leaves the corresponding BindingOptions pieces disabled.

type BindingOptions

type BindingOptions struct {
	Auth               *AuthConfig
	Ice                *IceConfig
	RequireFingerprint bool
}

BindingOptions enables optional auth and ICE behavior for generalized Binding helpers.

func (*BindingOptions) BuildAuthAttributes

func (opts *BindingOptions) BuildAuthAttributes() []Attribute

func (*BindingOptions) BuildIceAttributes

func (opts *BindingOptions) BuildIceAttributes() []Attribute

type BindingResult

type BindingResult struct {
	TransactionID [12]byte
	IP            net.IP
	Port          int
}

BindingResult captures the common result of a STUN Binding exchange.

func ProcessBindingResponse

func ProcessBindingResponse(response *Message, expectedTxID [12]byte, validateOpts *BindingOptions) (*BindingResult, error)

ProcessBindingResponse validates a Binding response and returns its common result.

func QueryServerTCP

func QueryServerTCP(stunServerAddr string, connOrLocalAddr any) (*BindingResult, error)

QueryServerTCP is a convenience function that queries a STUN server over TCP. It discovers the IP address and port as seen from the public internet.

func QueryServerTLS

func QueryServerTLS(stunServerAddr string, connOrLocalAddr any, tlsConfig *tls.Config) (*BindingResult, error)

QueryServerTLS is a convenience function that queries a STUN server over TLS. It discovers the IP address and port as seen from the public internet.

func QueryServerUDP

func QueryServerUDP(stunServerAddr string, connOrLocalAddr any) (*BindingResult, error)

QueryServerUDP is a convenience function that queries a STUN server over UDP. It discovers the IP address and port as seen from the public internet.

type Buffer

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

Buffer is a simple buffer that can be used to write STUN messages to. It implements the SerializeBuffer interface. This implementation mimics the behavior of bytes.Buffer, but allows the caller to directly access the requested portion of the buffer. The benefit is the ability to write raw binary data directly and reduce allocations. Buffer is not thread-safe.

func NewBuffer

func NewBuffer(buf []byte) *Buffer

NewBuffer creates a new Buffer from a byte slice, preserving its contents and setting the written position to len(buf). Use Buffer.Reset to clear the buffer and reset the written position.

func (*Buffer) Append

func (b *Buffer) Append(n int) []byte

Append appends n bytes to the buffer and returns a slice of the appended bytes for the caller to write to. The caller must write exactly n bytes to the returned slice.

func (*Buffer) Bytes

func (b *Buffer) Bytes() []byte

Bytes returns a slice of the buffer's contents, up to the written position. The returned slice is not a copy, and could be modified directly if needed.

func (*Buffer) Len

func (b *Buffer) Len() int

Len returns the number of bytes written to the buffer.

func (*Buffer) Reset

func (b *Buffer) Reset()

Reset resets the written position to 0, but keeps the underlying buffer, without zeroing the bytes.

func (*Buffer) Zero

func (b *Buffer) Zero()

Zero calls Reset() and then clears the buffer up to its capacity, zeroing all the bytes.

type Class

type Class uint16

Class is the 2-bit STUN class encoding defined in RFC 8489 Section 5.

const (
	ClassRequest         Class = 0x0000
	ClassIndication      Class = 0x0001
	ClassSuccessResponse Class = 0x0002
	ClassErrorResponse   Class = 0x0003
)

func MessageClass

func MessageClass(msgType uint16) Class

MessageClass extracts the STUN class from a raw STUN message type. The masks and shifts intentionally mirror RFC 8489 Appendix A.

func (Class) String

func (c Class) String() string

type Client

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

Client represents a STUN client with configurable settings

func NewClient

func NewClient(serverAddr string) *Client

NewClient creates a new STUN client instance. As a default, it will require a fingerprint in the response. Use WithBindingOptions() to customize the binding options.

func (*Client) QueryServer

func (c *Client) QueryServer(stunServer string, sourcePort int, protocol string, tlsConfig *tls.Config) (*BindingResult, error)

QueryServer performs a STUN query to the specified server and protocol. Valid protocols are "udp", "tcp" and "tls". It returns the binding result or an error if the query fails.

func (*Client) QueryStunServerTCP

func (c *Client) QueryStunServerTCP(connOrLocalAddr any) (*BindingResult, error)

QueryStunServerTCP takes a TCP connection or a source port and queries the STUN server over TCP. This method discovers your public IP address and port as seen from the internet. It accepts either an existing TCP connection (*net.TCPConn) or a local address (*net.TCPAddr). If a source port is provided, a new TCP connection will be established and closed after the query.

func (*Client) QueryStunServerTLS

func (c *Client) QueryStunServerTLS(connOrLocalAddr any, tlsConfig *tls.Config) (*BindingResult, error)

QueryStunServerTLS takes a TLS connection or a source port and queries the STUN server over TLS. This method discovers your public IP address and port as seen from the internet. It accepts either an existing TLS connection (*net.TCPConn) or a local address (*net.TCPAddr). If a source port is provided, a new TLS connection will be established and closed after the query.

func (*Client) QueryStunServerUDP

func (c *Client) QueryStunServerUDP(connOrLocalAddr any) (*BindingResult, error)

QueryStunServerUDP takes a UDP connection or a source port and queries the STUN server over UDP. This method discovers your public IP address and port as seen from the internet. It accepts either an existing UDP connection (*net.UDPConn) or a local address (*net.UDPAddr). If a source port is provided, a new UDP connection will be established and closed after the query.

func (*Client) WithBindingOptions

func (c *Client) WithBindingOptions(bindingOptions *BindingOptions) *Client

WithBindingOptions sets the binding options for the client.

func (*Client) WithDialer

func (c *Client) WithDialer(dialer *net.Dialer) *Client

WithDialer sets the network dialer for the client to a custom one initiated by the caller.

func (*Client) WithLoggerFunc

func (c *Client) WithLoggerFunc(loggerFunc LoggerFunc) *Client

WithLoggerFunc sets the logger function for the client.

func (*Client) WithReceiveTimeout

func (c *Client) WithReceiveTimeout(receiveTimeout time.Duration) *Client

WithReceiveTimeout sets the receive timeout for the client receive operations.

type ErrorCodeAttr

type ErrorCodeAttr struct {
	Code   int
	Reason string
}

ErrorCodeAttr implements Attribute for ERROR-CODE (0x0009). Code is the numeric error code (e.g. 401), Reason is the human-readable string. Implements the Attribute interface.

func NewErrorCodeAttr

func NewErrorCodeAttr(code int, reason string) *ErrorCodeAttr

NewErrorCodeAttr creates an ERROR-CODE attribute.

func (*ErrorCodeAttr) DecodeFromBytes

func (a *ErrorCodeAttr) DecodeFromBytes(b []byte) error

func (*ErrorCodeAttr) GetType

func (a *ErrorCodeAttr) GetType() uint16

func (*ErrorCodeAttr) IsICE

func (a *ErrorCodeAttr) IsICE() bool

func (*ErrorCodeAttr) SerializeLen

func (a *ErrorCodeAttr) SerializeLen() int

func (*ErrorCodeAttr) SerializeTo

func (a *ErrorCodeAttr) SerializeTo(sb SerializeBuffer) error

type FingerprintAttr

type FingerprintAttr struct {
	Value uint32
}

FingerprintAttr implements Attribute for FINGERPRINT (0x8028). Value is the 4-byte CRC-32. Implements the Attribute interface.

func NewFingerprintAttr

func NewFingerprintAttr(message []byte) *FingerprintAttr

NewFingerprintAttr creates a FINGERPRINT attribute. The input should be the entire message up to (but excluding) the FINGERPRINT attribute itself. Per RFC 5389, the CRC covers the message with the header Length field including the FINGERPRINT attribute (8 bytes), so we adjust the Length before hashing and restore it afterwards.

func (*FingerprintAttr) DecodeFromBytes

func (a *FingerprintAttr) DecodeFromBytes(b []byte) error

func (*FingerprintAttr) GetType

func (a *FingerprintAttr) GetType() uint16

func (*FingerprintAttr) IsICE

func (a *FingerprintAttr) IsICE() bool

func (*FingerprintAttr) SerializeLen

func (a *FingerprintAttr) SerializeLen() int

func (*FingerprintAttr) SerializeTo

func (a *FingerprintAttr) SerializeTo(sb SerializeBuffer) error
type Header struct {
	Type          uint16
	Length        uint16
	MagicCookie   uint32
	TransactionID [12]byte
}

Header represents the STUN message header.

func NewHeader

func NewHeader(msgType uint16, txID [12]byte) Header

NewHeader returns a Header with the given type, attribute length, and transaction ID.

func (*Header) DecodeFromBytes

func (h *Header) DecodeFromBytes(data []byte) error

DecodeFromBytes decodes the input bytes into the STUN header.

func (*Header) SerializeLen

func (h *Header) SerializeLen() int

SerializeLen returns the length of the serialized header.

func (*Header) SerializeTo

func (h *Header) SerializeTo(sb SerializeBuffer) error

SerializeTo serializes the header to a SerializeBuffer.

func (*Header) Validate

func (h *Header) Validate() error

Validate validates the basic STUN header properties.

type ICEControlledAttr

type ICEControlledAttr struct {
	Value uint64
}

ICEControlledAttr implements Attribute for ICE-CONTROLLED (0x8029). Implements the Attribute interface.

func NewICEControlledAttr

func NewICEControlledAttr(value uint64) *ICEControlledAttr

NewICEControlledAttr creates an ICE-CONTROLLED attribute.

func (*ICEControlledAttr) DecodeFromBytes

func (a *ICEControlledAttr) DecodeFromBytes(b []byte) error

func (*ICEControlledAttr) GetType

func (a *ICEControlledAttr) GetType() uint16

func (*ICEControlledAttr) IsICE

func (a *ICEControlledAttr) IsICE() bool

func (*ICEControlledAttr) SerializeLen

func (a *ICEControlledAttr) SerializeLen() int

func (*ICEControlledAttr) SerializeTo

func (a *ICEControlledAttr) SerializeTo(sb SerializeBuffer) error

type ICEControllingAttr

type ICEControllingAttr struct {
	Value uint64
}

ICEControllingAttr implements Attribute for ICE-CONTROLLING (0x802A). Implements the Attribute interface.

func NewICEControllingAttr

func NewICEControllingAttr(value uint64) *ICEControllingAttr

NewICEControllingAttr creates an ICE-CONTROLLING attribute.

func (*ICEControllingAttr) DecodeFromBytes

func (a *ICEControllingAttr) DecodeFromBytes(b []byte) error

func (*ICEControllingAttr) GetType

func (a *ICEControllingAttr) GetType() uint16

func (*ICEControllingAttr) IsICE

func (a *ICEControllingAttr) IsICE() bool

func (*ICEControllingAttr) SerializeLen

func (a *ICEControllingAttr) SerializeLen() int

func (*ICEControllingAttr) SerializeTo

func (a *ICEControllingAttr) SerializeTo(sb SerializeBuffer) error

type ICEPriorityAttr

type ICEPriorityAttr struct {
	Value uint32
}

ICEPriorityAttr implements Attribute for PRIORITY (0x0024). Implements the Attribute interface.

func NewICEPriorityAttr

func NewICEPriorityAttr(value uint32) *ICEPriorityAttr

NewICEPriorityAttr creates a PRIORITY attribute.

func (*ICEPriorityAttr) DecodeFromBytes

func (a *ICEPriorityAttr) DecodeFromBytes(b []byte) error

func (*ICEPriorityAttr) GetType

func (a *ICEPriorityAttr) GetType() uint16

func (*ICEPriorityAttr) IsICE

func (a *ICEPriorityAttr) IsICE() bool

func (*ICEPriorityAttr) SerializeLen

func (a *ICEPriorityAttr) SerializeLen() int

func (*ICEPriorityAttr) SerializeTo

func (a *ICEPriorityAttr) SerializeTo(sb SerializeBuffer) error

type ICEUseCandidateAttr

type ICEUseCandidateAttr struct{}

ICEUseCandidateAttr implements Attribute for USE-CANDIDATE (0x0025). Implements the Attribute interface.

func NewICEUseCandidateAttr

func NewICEUseCandidateAttr() *ICEUseCandidateAttr

NewICEUseCandidateAttr creates a USE-CANDIDATE attribute.

func (*ICEUseCandidateAttr) DecodeFromBytes

func (a *ICEUseCandidateAttr) DecodeFromBytes(b []byte) error

func (*ICEUseCandidateAttr) GetType

func (a *ICEUseCandidateAttr) GetType() uint16

func (*ICEUseCandidateAttr) IsICE

func (a *ICEUseCandidateAttr) IsICE() bool

func (*ICEUseCandidateAttr) SerializeLen

func (a *ICEUseCandidateAttr) SerializeLen() int

func (*ICEUseCandidateAttr) SerializeTo

func (a *ICEUseCandidateAttr) SerializeTo(sb SerializeBuffer) error

type IceAuth

type IceAuth struct {
	LocalUfrag     string
	LocalPassword  string
	RemoteUfrag    string
	RemotePassword string
}

IceAuth represents ICE-specific STUN credential semantics. ICE uses username fragments to build the STUN USERNAME attribute and selects different passwords for outgoing vs incoming requests.

func (*IceAuth) ExpectedAuth

func (a *IceAuth) ExpectedAuth() *AuthConfig

ExpectedAuth returns the generic STUN auth attributes expected from the peer.

func (*IceAuth) ExpectedIncomingUsername

func (a *IceAuth) ExpectedIncomingUsername() string

ExpectedIncomingUsername returns the ICE username value expected from the peer.

func (*IceAuth) IncomingRequestPassword

func (a *IceAuth) IncomingRequestPassword() string

IncomingRequestPassword returns the password used to validate incoming ICE requests and integrity-protect the corresponding responses.

func (*IceAuth) OutgoingRequestPassword

func (a *IceAuth) OutgoingRequestPassword() string

OutgoingRequestPassword returns the password used to integrity-protect outgoing ICE requests.

func (*IceAuth) OutgoingUsername

func (a *IceAuth) OutgoingUsername() string

OutgoingUsername returns the ICE username value for an outgoing request.

func (*IceAuth) RequestAuth

func (a *IceAuth) RequestAuth() *AuthConfig

RequestAuth returns the generic STUN auth attributes for an outgoing ICE request.

type IceConfig

type IceConfig struct {
	Priority       uint32
	UseCandidate   bool
	IceControlling uint64
	IceControlled  uint64
}

IceConfig represents ICE-specific STUN attributes.

func ParseIceAttributesFromBytes

func ParseIceAttributesFromBytes(data []byte) (*IceConfig, error)

ParseIceAttributesFromBytes parses ICE-specific attributes from a byte slice.

func ParseIceAttributesFromMessage

func ParseIceAttributesFromMessage(message *Message) (*IceConfig, error)

ParseIceAttributesFromMessage parses ICE-specific attributes from a STUN message.

type LoggerFunc

type LoggerFunc func(level string, args ...any)

LoggerFunc is a generic function that logs a message.

var NoopLoggerFunc LoggerFunc = func(level string, args ...any) {}

type Message

type Message struct {
	// Header is the header of the message.
	Header Header
	// Attributes is the list of attributes in the message
	// in the order they appear when serialized.
	Attributes []Attribute
	// Raw is the raw bytes of the message.
	Raw Buffer
	// contains filtered or unexported fields
}

Message represents a STUN message with its header and attributes. Properties are exported but should not be modified directly, unless you know what you are doing.

func BuildBindingRequest

func BuildBindingRequest(opts *BindingOptions) (*Message, error)

BuildBindingRequest creates a Binding request with optional auth and ICE attributes.

func CreateAuthenticatedErrorMessage

func CreateAuthenticatedErrorMessage(txID [12]byte, code int, reason string, auth *AuthConfig) (*Message, error)

CreateAuthenticatedErrorMessage creates a STUN error response with authentication attributes. Where authentication is not required, call CreateErrorMessage instead. Per RFC 8445, Username is omitted from error responses.

func CreateErrorMessage

func CreateErrorMessage(txID [12]byte, code int, reason string) (*Message, error)

CreateErrorMessage creates a STUN error message.

func DecodeMessage

func DecodeMessage(data []byte) (*Message, error)

DecodeMessage parses a raw STUN message into its components. This is equivalent to calling msg.DecodeFromBytes(data) on a new Message.

func NewMessage

func NewMessage(msgType uint16, attrs []Attribute) (*Message, error)

NewMessage creates a new STUN message with the given type and attributes (random txID).

func NewMessageWithTransactionID

func NewMessageWithTransactionID(msgType uint16, attrs []Attribute, txID [12]byte) (*Message, error)

NewMessageWithTransactionID creates a new STUN message with the given type, attributes, and transaction ID.

func ProcessBindingRequest

func ProcessBindingRequest(request *Message, remoteAddr net.Addr, validateOpts, opts *BindingOptions) (*Message, error)

ProcessBindingRequest validates a Binding request and builds its response.

func ReceiveMessageFromConn

func ReceiveMessageFromConn(conn net.Conn) (message *Message, err error)

ReceiveMessageFromConn receives a STUN message from a connection.

func (*Message) AddFingerprint

func (msg *Message) AddFingerprint() error

AddFingerprint appends the FINGERPRINT attribute to a STUN message.

func (*Message) AddMessageIntegrity

func (msg *Message) AddMessageIntegrity(password string) error

AddMessageIntegrity adds the MESSAGE-INTEGRITY attribute (HMAC-SHA1) to a STUN message. It is equivalent to calling AddMessageIntegrityWithHash with AttrMessageIntegrity and sha1.New.

func (*Message) AddMessageIntegritySHA256

func (msg *Message) AddMessageIntegritySHA256(password string) error

AddMessageIntegritySHA256 adds the MESSAGE-INTEGRITY-SHA256 attribute (HMAC-SHA256) to a STUN message. It is equivalent to calling AddMessageIntegrityWithHash with AttrMessageIntegritySHA256 and sha256.New.

func (*Message) AddMessageIntegrityWithHash

func (msg *Message) AddMessageIntegrityWithHash(password string, attrType uint16, newHash func() hash.Hash) error

AddMessageIntegrityWithHash adds a given message-integrity attribute to a STUN message. It handles the two-phase integrity calculation and uses attrType and newHash for the algorithm.

func (*Message) AppendAttribute

func (msg *Message) AppendAttribute(attrs ...Attribute) error

AppendAttribute appends one or more attributes to the message. The method enforces the requirement that you cannot append attributes after a FINGERPRINT attribute. You can only append MESSAGE-INTEGRITY-SHA256 or FINGERPRINT attributes after a MESSAGE-INTEGRITY attribute. You can only append the FINGERPRINT attribute after a MESSAGE-INTEGRITY-SHA256 attribute.

func (*Message) DecodeFromBytes

func (msg *Message) DecodeFromBytes(data []byte) error

DecodeFromBytes decodes the input bytes into the STUN message.

func (*Message) FindAttribute

func (msg *Message) FindAttribute(attrType uint16) (Attribute, bool)

FindAttribute returns the first attribute with the given type.

func (*Message) GetAuthParams

func (msg *Message) GetAuthParams() (*AuthConfig, error)

GetAuthParams extracts authentication attributes (Username, Realm, Nonce) from a STUN message.

func (*Message) MappedAddrPort

func (msg *Message) MappedAddrPort() (net.IP, int, error)

MappedAddrPort extracts the mapped address and port from a STUN response.

func (*Message) ParseError

func (msg *Message) ParseError() (ErrorCodeAttr, error)

ParseError extracts error code and reason from a STUN message.

func (*Message) SerializeLen

func (msg *Message) SerializeLen() int

SerializeLen returns the total serialized length of the message.

func (*Message) SerializeTo

func (msg *Message) SerializeTo(sb SerializeBuffer) error

SerializeTo writes the message using SerializeBuffer.

func (*Message) SerializeToRaw

func (msg *Message) SerializeToRaw() error

SerializeToRaw clears the internal Raw buffer and serializes the full message to it. You should call this method after manually modifying any of the message's attributes. It is equivalent to calling SerializeTo(&msg.Raw).

func (*Message) Validate

func (msg *Message) Validate(opts *BindingOptions) error

Validate validates the message header. TODO: Add more validation.

func (*Message) VerifyFingerprint

func (msg *Message) VerifyFingerprint() bool

VerifyFingerprint verifies the FINGERPRINT attribute in a STUN message.

func (*Message) VerifyMessageIntegrity

func (msg *Message) VerifyMessageIntegrity(password string) (bool, error)

VerifyMessageIntegrity verifies the MESSAGE-INTEGRITY attribute (HMAC-SHA1) in a STUN message. It is equivalent to calling VerifyMessageIntegrityWithHash with AttrMessageIntegrity and sha1.New.

func (*Message) VerifyMessageIntegritySHA256

func (msg *Message) VerifyMessageIntegritySHA256(password string) (bool, error)

VerifyMessageIntegritySHA256 verifies the MESSAGE-INTEGRITY-SHA256 attribute (HMAC-SHA256) in a STUN message. It is equivalent to calling VerifyMessageIntegrityWithHash with AttrMessageIntegritySHA256 and sha256.New.

func (*Message) VerifyMessageIntegrityWithHash

func (msg *Message) VerifyMessageIntegrityWithHash(password string, attrType uint16, newHash func() hash.Hash) (bool, error)

VerifyMessageIntegrityWithHash verifies the given message-integrity attribute in a STUN message. It searches for attrType, computes expected integrity using newHash, and compares.

func (*Message) WithFingerprint

func (msg *Message) WithFingerprint() *Message

WithFingerprint sets the message to compute and add a FINGERPRINT attribute to the message before serializing it or writing it to a writer.

func (*Message) WriteTo

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

WriteTo writes the message to a writer, e.g. a socket (net.Conn) or file.

type MessageIntegrityAttr

type MessageIntegrityAttr struct {
	Value [20]byte
}

MessageIntegrityAttr implements Attribute for MESSAGE-INTEGRITY (0x0008). Value is the 20-byte HMAC-SHA1. Implements the Attribute interface.

func NewMessageIntegrityAttr

func NewMessageIntegrityAttr(value [20]byte) *MessageIntegrityAttr

NewMessageIntegrityAttr creates a MESSAGE-INTEGRITY attribute.

func (*MessageIntegrityAttr) DecodeFromBytes

func (a *MessageIntegrityAttr) DecodeFromBytes(b []byte) error

func (*MessageIntegrityAttr) GetType

func (a *MessageIntegrityAttr) GetType() uint16

func (*MessageIntegrityAttr) IsICE

func (a *MessageIntegrityAttr) IsICE() bool

func (*MessageIntegrityAttr) SerializeLen

func (a *MessageIntegrityAttr) SerializeLen() int

func (*MessageIntegrityAttr) SerializeTo

func (a *MessageIntegrityAttr) SerializeTo(sb SerializeBuffer) error

type MessageIntegritySHA256Attr

type MessageIntegritySHA256Attr struct {
	Value [32]byte
}

MessageIntegritySHA256Attr implements Attribute for MESSAGE-INTEGRITY-SHA256 (0x001C). Value is the 32-byte HMAC-SHA256. Implements the Attribute interface.

func NewMessageIntegritySHA256Attr

func NewMessageIntegritySHA256Attr(value [32]byte) *MessageIntegritySHA256Attr

NewMessageIntegritySHA256Attr creates a MESSAGE-INTEGRITY-SHA256 attribute.

func (*MessageIntegritySHA256Attr) DecodeFromBytes

func (a *MessageIntegritySHA256Attr) DecodeFromBytes(b []byte) error

func (*MessageIntegritySHA256Attr) GetType

func (a *MessageIntegritySHA256Attr) GetType() uint16

func (*MessageIntegritySHA256Attr) IsICE

func (a *MessageIntegritySHA256Attr) IsICE() bool

func (*MessageIntegritySHA256Attr) SerializeLen

func (a *MessageIntegritySHA256Attr) SerializeLen() int

func (*MessageIntegritySHA256Attr) SerializeTo

type Method

type Method uint16

Method is the 12-bit STUN method encoding defined in RFC 8489 Section 5.

const (
	MethodBinding Method = 0x0001
)

func MessageMethod

func MessageMethod(msgType uint16) Method

MessageMethod extracts the STUN method from a raw STUN message type. The masks and shifts intentionally mirror RFC 8489 Appendix A.

func (Method) String

func (m Method) String() string

type NonceAttr

type NonceAttr struct {
	Value string
}

NonceAttr implements Attribute for NONCE (0x0015). Implements the Attribute interface.

func NewNonceAttr

func NewNonceAttr(value string) *NonceAttr

NewNonceAttr creates a NONCE attribute.

func (*NonceAttr) DecodeFromBytes

func (a *NonceAttr) DecodeFromBytes(b []byte) error

func (*NonceAttr) GetType

func (a *NonceAttr) GetType() uint16

func (*NonceAttr) IsICE

func (a *NonceAttr) IsICE() bool

func (*NonceAttr) SerializeLen

func (a *NonceAttr) SerializeLen() int

func (*NonceAttr) SerializeTo

func (a *NonceAttr) SerializeTo(sb SerializeBuffer) error

type RealmAttr

type RealmAttr struct {
	Value string
}

RealmAttr implements Attribute for REALM (0x0014). Implements the Attribute interface.

func NewRealmAttr

func NewRealmAttr(value string) *RealmAttr

NewRealmAttr creates a REALM attribute.

func (*RealmAttr) DecodeFromBytes

func (a *RealmAttr) DecodeFromBytes(b []byte) error

func (*RealmAttr) GetType

func (a *RealmAttr) GetType() uint16

func (*RealmAttr) IsICE

func (a *RealmAttr) IsICE() bool

func (*RealmAttr) SerializeLen

func (a *RealmAttr) SerializeLen() int

func (*RealmAttr) SerializeTo

func (a *RealmAttr) SerializeTo(sb SerializeBuffer) error

type Serializable

type Serializable interface {
	// SerializeLen returns the length of the serialized object over the wire.
	SerializeLen() int
	// SerializeTo serializes the object to a SerializeBuffer.
	SerializeTo(sb SerializeBuffer) error
}

Serializable is the interface that represents a serializable object.

type SerializeBuffer

type SerializeBuffer interface {
	// Len returns the number of bytes written to the buffer.
	Len() int
	// Append appends n bytes to the buffer and returns a slice of the appended bytes
	// for the caller to write to. The caller must write exactly n bytes to the
	// returned slice.
	Append(n int) []byte
	// Bytes returns a slice of the buffer's contents.
	Bytes() []byte
	// Reset clears the buffer and resets the written position to 0.
	Reset()
}

SerializeBuffer is a helper used to write stun messages to the wire. It is inspired by the github.com/google/gopacket/layers.SerializeBuffer interface, although the implementation differs.

type Server

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

Server represents a STUN server. It listens on a given address and handles STUN requests. It's backed by a worker pool to process requests more efficiently. Callers must use the Listen method to start the server and the Close method to stop it.

func NewServer

func NewServer(config *ServerConfig) (*Server, error)

NewServer creates a new STUN server instance with the given configuration.

func (*Server) Close

func (s *Server) Close() error

Close closes the STUN server and frees up resources.

func (*Server) Listen

func (s *Server) Listen(ctx context.Context, listenAddr net.Addr) error

Listen starts the STUN server and listens on the given address.

func (*Server) WaitClose

func (s *Server) WaitClose()

WaitClose waits for the worker pool to finish processing all work items after the server is closed.

type ServerConfig

type ServerConfig struct {
	Logger LoggerFunc
	// TLS configuration for the STUN server
	TLSConfig *tls.Config
	// Number of workers that the STUN server will spawn to process requests
	// When 0, the number of workers will be set to the number of CPU cores
	Workers int
	// Function that will be used to get a buffer from the buffer pool
	// When nil, memory will be allocated on the fly
	GetBufferFunc func() []byte
	// Function that will be used to put a buffer back into the buffer pool
	// When nil, the buffer will be discarded
	PutBufferFunc func([]byte)
	// Function that will be used to listen on UDP, this is particularly useful for custom listeners like QUIC or DTLS,
	// or where specific network configuration is required (e.g. reuseaddr, reuseport, etc.).
	// When nil, the default UDP listener will be used (net.ListenUDP).
	UDPListenFunc func(network string, listenAddr *net.UDPAddr) (*net.UDPConn, error)
	// Function that will be used to listen on TCP, this is particularly useful for custom listeners,
	// or where specific network configuration is required (e.g. reuseaddr, reuseport, etc.).
	// When nil, the default TCP listener will be used (net.ListenTCP).
	TCPListenFunc func(network string, listenAddr *net.TCPAddr) (*net.TCPListener, error)
}

ServerConfig is the configuration for a STUN server.

type UnknownAttr

type UnknownAttr struct {
	Type  uint16
	Value []byte
}

UnknownAttr holds an attribute type not in the registry for round-trip. Implements the Attribute interface.

func (*UnknownAttr) DecodeFromBytes

func (a *UnknownAttr) DecodeFromBytes(b []byte) error

func (*UnknownAttr) GetType

func (a *UnknownAttr) GetType() uint16

func (*UnknownAttr) IsICE

func (a *UnknownAttr) IsICE() bool

func (*UnknownAttr) SerializeLen

func (a *UnknownAttr) SerializeLen() int

func (*UnknownAttr) SerializeTo

func (a *UnknownAttr) SerializeTo(sb SerializeBuffer) error

type UsernameAttr

type UsernameAttr struct {
	Value string
}

UsernameAttr implements Attribute for USERNAME (0x0006). Implements the Attribute interface.

func NewUsernameAttr

func NewUsernameAttr(value string) *UsernameAttr

NewUsernameAttr creates a USERNAME attribute.

func (*UsernameAttr) DecodeFromBytes

func (a *UsernameAttr) DecodeFromBytes(b []byte) error

func (*UsernameAttr) GetType

func (a *UsernameAttr) GetType() uint16

func (*UsernameAttr) IsICE

func (a *UsernameAttr) IsICE() bool

func (*UsernameAttr) SerializeLen

func (a *UsernameAttr) SerializeLen() int

func (*UsernameAttr) SerializeTo

func (a *UsernameAttr) SerializeTo(sb SerializeBuffer) error

type XorMappedAddressAttr

type XorMappedAddressAttr struct {
	Value []byte
}

XorMappedAddressAttr implements Attribute for XOR-MAPPED-ADDRESS (0x0020). Value holds the raw attribute value (reserved, family, xor'd port, xor'd IP). Implements the Attribute interface.

func NewXorMappedAddressAttr

func NewXorMappedAddressAttr(addr net.Addr, txID [12]byte) (*XorMappedAddressAttr, error)

NewXorMappedAddressAttr creates an XOR-MAPPED-ADDRESS attribute using CreateXorMappedAddress.

func (*XorMappedAddressAttr) DecodeFromBytes

func (a *XorMappedAddressAttr) DecodeFromBytes(b []byte) error

func (*XorMappedAddressAttr) DecodeXorMappedAddress

func (a *XorMappedAddressAttr) DecodeXorMappedAddress(txID [12]byte) (net.IP, int, error)

DecodeXorMappedAddress decodes Value (raw XOR'd bytes) into IP and port using txID.

func (*XorMappedAddressAttr) GetType

func (a *XorMappedAddressAttr) GetType() uint16

func (*XorMappedAddressAttr) IsICE

func (a *XorMappedAddressAttr) IsICE() bool

func (*XorMappedAddressAttr) SerializeLen

func (a *XorMappedAddressAttr) SerializeLen() int

func (*XorMappedAddressAttr) SerializeTo

func (a *XorMappedAddressAttr) SerializeTo(sb SerializeBuffer) error

Jump to

Keyboard shortcuts

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