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
- Variables
- func CalculateFingerprint(message []byte) uint32
- func CalculateShortTermMessageIntegrity(message []byte, password string) []byte
- func CalculateShortTermMessageIntegritySHA256(message []byte, password string) []byte
- func CalculateShortTermMessageIntegrityWithHash(message []byte, password string, attrType uint16, newHash func() hash.Hash) []byte
- func CreateXorMappedAddress(addr net.Addr, txID [12]byte) ([]byte, error)
- func EncodeMessageType(method Method, class Class) uint16
- func IsErrorResponseType(msgType uint16) bool
- func IsIndicationType(msgType uint16) bool
- func IsRequestType(msgType uint16) bool
- func IsSuccessResponseType(msgType uint16) bool
- func OpaqueString(s string) string
- func SendErrorResponse(conn net.Conn, transactionID [12]byte, code int, reason string, ...) error
- func ValidateMethodAndClass(msgType uint16, expectedMethod Method, allowedClasses ...Class) error
- func ValidateShortTermIntegrity(request *Message, expected *AuthConfig) error
- type Attribute
- type AuthConfig
- type BindingAgent
- func (b *BindingAgent) HandleRequest(request *Message) error
- func (b *BindingAgent) HandleResponse(response *Message, transactionID [12]byte) (*BindingResult, error)
- func (b *BindingAgent) ICENominateCandidate() (*BindingResult, error)
- func (b *BindingAgent) ICENominated() bool
- func (b *BindingAgent) ICEPriority() uint32
- func (b *BindingAgent) Receive()
- func (b *BindingAgent) SendRequest(waitForResponse bool) (result *BindingResult, err error)
- func (b *BindingAgent) SetConfig(config *BindingAgentConfig)
- func (b *BindingAgent) SetConn(conn net.Conn)
- func (b *BindingAgent) StopReceive()
- type BindingAgentConfig
- func NewBindingAgentConfig(logger LoggerFunc, auth *AuthConfig) *BindingAgentConfig
- func NewControlledICEBindingAgentConfig(logger LoggerFunc, auth *IceAuth, priority uint32) *BindingAgentConfig
- func NewControllingICEBindingAgentConfig(logger LoggerFunc, auth *IceAuth, priority uint32) *BindingAgentConfig
- func NewICEBindingAgentConfig(logger LoggerFunc, iceAuth *IceAuth, attributes *IceConfig) *BindingAgentConfig
- type BindingOptions
- type BindingResult
- func ProcessBindingResponse(response *Message, expectedTxID [12]byte, validateOpts *BindingOptions) (*BindingResult, error)
- func QueryServerTCP(stunServerAddr string, connOrLocalAddr any) (*BindingResult, error)
- func QueryServerTLS(stunServerAddr string, connOrLocalAddr any, tlsConfig *tls.Config) (*BindingResult, error)
- func QueryServerUDP(stunServerAddr string, connOrLocalAddr any) (*BindingResult, error)
- type Buffer
- type Class
- type Client
- func (c *Client) QueryServer(stunServer string, sourcePort int, protocol string, tlsConfig *tls.Config) (*BindingResult, error)
- func (c *Client) QueryStunServerTCP(connOrLocalAddr any) (*BindingResult, error)
- func (c *Client) QueryStunServerTLS(connOrLocalAddr any, tlsConfig *tls.Config) (*BindingResult, error)
- func (c *Client) QueryStunServerUDP(connOrLocalAddr any) (*BindingResult, error)
- func (c *Client) WithBindingOptions(bindingOptions *BindingOptions) *Client
- func (c *Client) WithDialer(dialer *net.Dialer) *Client
- func (c *Client) WithLoggerFunc(loggerFunc LoggerFunc) *Client
- func (c *Client) WithReceiveTimeout(receiveTimeout time.Duration) *Client
- type ErrorCodeAttr
- type FingerprintAttr
- type Header
- type ICEControlledAttr
- type ICEControllingAttr
- type ICEPriorityAttr
- type ICEUseCandidateAttr
- type IceAuth
- type IceConfig
- type LoggerFunc
- type Message
- func BuildBindingRequest(opts *BindingOptions) (*Message, error)
- func CreateAuthenticatedErrorMessage(txID [12]byte, code int, reason string, auth *AuthConfig) (*Message, error)
- func CreateErrorMessage(txID [12]byte, code int, reason string) (*Message, error)
- func DecodeMessage(data []byte) (*Message, error)
- func NewMessage(msgType uint16, attrs []Attribute) (*Message, error)
- func NewMessageWithTransactionID(msgType uint16, attrs []Attribute, txID [12]byte) (*Message, error)
- func ProcessBindingRequest(request *Message, remoteAddr net.Addr, validateOpts, opts *BindingOptions) (*Message, error)
- func ReceiveMessageFromConn(conn net.Conn) (message *Message, err error)
- func (msg *Message) AddFingerprint() error
- func (msg *Message) AddMessageIntegrity(password string) error
- func (msg *Message) AddMessageIntegritySHA256(password string) error
- func (msg *Message) AddMessageIntegrityWithHash(password string, attrType uint16, newHash func() hash.Hash) error
- func (msg *Message) AppendAttribute(attrs ...Attribute) error
- func (msg *Message) DecodeFromBytes(data []byte) error
- func (msg *Message) FindAttribute(attrType uint16) (Attribute, bool)
- func (msg *Message) GetAuthParams() (*AuthConfig, error)
- func (msg *Message) MappedAddrPort() (net.IP, int, error)
- func (msg *Message) ParseError() (ErrorCodeAttr, error)
- func (msg *Message) SerializeLen() int
- func (msg *Message) SerializeTo(sb SerializeBuffer) error
- func (msg *Message) SerializeToRaw() error
- func (msg *Message) Validate(opts *BindingOptions) error
- func (msg *Message) VerifyFingerprint() bool
- func (msg *Message) VerifyMessageIntegrity(password string) (bool, error)
- func (msg *Message) VerifyMessageIntegritySHA256(password string) (bool, error)
- func (msg *Message) VerifyMessageIntegrityWithHash(password string, attrType uint16, newHash func() hash.Hash) (bool, error)
- func (msg *Message) WithFingerprint() *Message
- func (msg *Message) WriteTo(w io.Writer) (int64, error)
- type MessageIntegrityAttr
- type MessageIntegritySHA256Attr
- func (a *MessageIntegritySHA256Attr) DecodeFromBytes(b []byte) error
- func (a *MessageIntegritySHA256Attr) GetType() uint16
- func (a *MessageIntegritySHA256Attr) IsICE() bool
- func (a *MessageIntegritySHA256Attr) SerializeLen() int
- func (a *MessageIntegritySHA256Attr) SerializeTo(sb SerializeBuffer) error
- type Method
- type NonceAttr
- type RealmAttr
- type Serializable
- type SerializeBuffer
- type Server
- type ServerConfig
- type UnknownAttr
- type UsernameAttr
- type XorMappedAddressAttr
- func (a *XorMappedAddressAttr) DecodeFromBytes(b []byte) error
- func (a *XorMappedAddressAttr) DecodeXorMappedAddress(txID [12]byte) (net.IP, int, error)
- func (a *XorMappedAddressAttr) GetType() uint16
- func (a *XorMappedAddressAttr) IsICE() bool
- func (a *XorMappedAddressAttr) SerializeLen() int
- func (a *XorMappedAddressAttr) SerializeTo(sb SerializeBuffer) error
Constants ¶
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 )
const ( AttrICEPriority uint16 = 0x0024 AttrICEUseCandidate uint16 = 0x0025 AttrICEControlled uint16 = 0x8029 AttrICEControlling uint16 = 0x802A )
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 ¶
var ErrParseMessage = errors.New("failed to parse STUN message")
var StunClassStrings = map[Class]string{ ClassRequest: "request", ClassIndication: "indication", ClassSuccessResponse: "success response", ClassErrorResponse: "error response", }
var StunMethodStrings = map[Method]string{ MethodBinding: "binding", }
Functions ¶
func CalculateFingerprint ¶
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 ¶
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 ¶
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 ¶
CreateXorMappedAddress creates a full, raw XOR-MAPPED-ADDRESS attribute for the given address and transaction ID.
func EncodeMessageType ¶
EncodeMessageType encodes a STUN method and class into the wire value. The masks and shifts intentionally mirror RFC 8489 Appendix A.
func IsErrorResponseType ¶
IsErrorResponseType reports whether the raw STUN message type is an error response.
func IsIndicationType ¶
IsIndicationType reports whether the raw STUN message type is an indication.
func IsRequestType ¶
IsRequestType reports whether the raw STUN message type is a request.
func IsSuccessResponseType ¶
IsSuccessResponseType reports whether the raw STUN message type is a success response.
func OpaqueString ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
type Class ¶
type Class uint16
Class is the 2-bit STUN class encoding defined in RFC 8489 Section 5.
func MessageClass ¶
MessageClass extracts the STUN class from a raw STUN message type. The masks and shifts intentionally mirror RFC 8489 Appendix A.
type Client ¶
type Client struct {
ServerAddr string
// contains filtered or unexported fields
}
Client represents a STUN client with configurable settings
func NewClient ¶
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 ¶
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.
type ErrorCodeAttr ¶
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 ¶
Header represents the STUN message header.
func NewHeader ¶
NewHeader returns a Header with the given type, attribute length, and transaction ID.
func (*Header) DecodeFromBytes ¶
DecodeFromBytes decodes the input bytes into the STUN header.
func (*Header) SerializeLen ¶
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.
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 ¶
ExpectedIncomingUsername returns the ICE username value expected from the peer.
func (*IceAuth) IncomingRequestPassword ¶
IncomingRequestPassword returns the password used to validate incoming ICE requests and integrity-protect the corresponding responses.
func (*IceAuth) OutgoingRequestPassword ¶
OutgoingRequestPassword returns the password used to integrity-protect outgoing ICE requests.
func (*IceAuth) OutgoingUsername ¶
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 ¶
ParseIceAttributesFromBytes parses ICE-specific attributes from a byte slice.
func ParseIceAttributesFromMessage ¶
ParseIceAttributesFromMessage parses ICE-specific attributes from a STUN message.
type LoggerFunc ¶
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 ¶
CreateErrorMessage creates a STUN error message.
func DecodeMessage ¶
DecodeMessage parses a raw STUN message into its components. This is equivalent to calling msg.DecodeFromBytes(data) on a new Message.
func NewMessage ¶
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 ¶
ReceiveMessageFromConn receives a STUN message from a connection.
func (*Message) AddFingerprint ¶
AddFingerprint appends the FINGERPRINT attribute to a STUN message.
func (*Message) AddMessageIntegrity ¶
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 ¶
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 ¶
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 ¶
DecodeFromBytes decodes the input bytes into the STUN message.
func (*Message) FindAttribute ¶
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 ¶
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 ¶
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 ¶
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 ¶
VerifyFingerprint verifies the FINGERPRINT attribute in a STUN message.
func (*Message) VerifyMessageIntegrity ¶
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 ¶
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 ¶
WithFingerprint sets the message to compute and add a FINGERPRINT attribute to the message before serializing it or writing it to a writer.
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 ¶
func (a *MessageIntegritySHA256Attr) SerializeTo(sb SerializeBuffer) error
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 ¶
MessageMethod extracts the STUN method from a raw STUN message type. The masks and shifts intentionally mirror RFC 8489 Appendix A.
type NonceAttr ¶
type NonceAttr struct {
Value string
}
NonceAttr implements Attribute for NONCE (0x0015). Implements the Attribute interface.
func NewNonceAttr ¶
NewNonceAttr creates a NONCE attribute.
func (*NonceAttr) DecodeFromBytes ¶
func (*NonceAttr) SerializeLen ¶
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 ¶
NewRealmAttr creates a REALM attribute.
func (*RealmAttr) DecodeFromBytes ¶
func (*RealmAttr) SerializeLen ¶
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.
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 ¶
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 ¶
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