| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
- // SPDX-License-Identifier: MIT
- package ice
- import (
- "net"
- "time"
- "github.com/pion/logging"
- "github.com/pion/stun"
- "github.com/pion/transport/v2"
- "golang.org/x/net/proxy"
- )
- const (
- // defaultCheckInterval is the interval at which the agent performs candidate checks in the connecting phase
- defaultCheckInterval = 200 * time.Millisecond
- // keepaliveInterval used to keep candidates alive
- defaultKeepaliveInterval = 2 * time.Second
- // defaultDisconnectedTimeout is the default time till an Agent transitions disconnected
- defaultDisconnectedTimeout = 5 * time.Second
- // defaultFailedTimeout is the default time till an Agent transitions to failed after disconnected
- defaultFailedTimeout = 25 * time.Second
- // defaultHostAcceptanceMinWait is the wait time before nominating a host candidate
- defaultHostAcceptanceMinWait = 0
- // defaultSrflxAcceptanceMinWait is the wait time before nominating a srflx candidate
- defaultSrflxAcceptanceMinWait = 500 * time.Millisecond
- // defaultPrflxAcceptanceMinWait is the wait time before nominating a prflx candidate
- defaultPrflxAcceptanceMinWait = 1000 * time.Millisecond
- // defaultRelayAcceptanceMinWait is the wait time before nominating a relay candidate
- defaultRelayAcceptanceMinWait = 2000 * time.Millisecond
- // defaultMaxBindingRequests is the maximum number of binding requests before considering a pair failed
- defaultMaxBindingRequests = 7
- // TCPPriorityOffset is a number which is subtracted from the default (UDP) candidate type preference
- // for host, srflx and prfx candidate types.
- defaultTCPPriorityOffset = 27
- // maxBufferSize is the number of bytes that can be buffered before we start to error
- maxBufferSize = 1000 * 1000 // 1MB
- // maxBindingRequestTimeout is the wait time before binding requests can be deleted
- maxBindingRequestTimeout = 4000 * time.Millisecond
- )
- func defaultCandidateTypes() []CandidateType {
- return []CandidateType{CandidateTypeHost, CandidateTypeServerReflexive, CandidateTypeRelay}
- }
- // AgentConfig collects the arguments to ice.Agent construction into
- // a single structure, for future-proofness of the interface
- type AgentConfig struct {
- Urls []*stun.URI
- // PortMin and PortMax are optional. Leave them 0 for the default UDP port allocation strategy.
- PortMin uint16
- PortMax uint16
- // LocalUfrag and LocalPwd values used to perform connectivity
- // checks. The values MUST be unguessable, with at least 128 bits of
- // random number generator output used to generate the password, and
- // at least 24 bits of output to generate the username fragment.
- LocalUfrag string
- LocalPwd string
- // MulticastDNSMode controls mDNS behavior for the ICE agent
- MulticastDNSMode MulticastDNSMode
- // MulticastDNSHostName controls the hostname for this agent. If none is specified a random one will be generated
- MulticastDNSHostName string
- // DisconnectedTimeout defaults to 5 seconds when this property is nil.
- // If the duration is 0, the ICE Agent will never go to disconnected
- DisconnectedTimeout *time.Duration
- // FailedTimeout defaults to 25 seconds when this property is nil.
- // If the duration is 0, we will never go to failed.
- FailedTimeout *time.Duration
- // KeepaliveInterval determines how often should we send ICE
- // keepalives (should be less then connectiontimeout above)
- // when this is nil, it defaults to 10 seconds.
- // A keepalive interval of 0 means we never send keepalive packets
- KeepaliveInterval *time.Duration
- // CheckInterval controls how often our task loop runs when in the
- // connecting state.
- CheckInterval *time.Duration
- // NetworkTypes is an optional configuration for disabling or enabling
- // support for specific network types.
- NetworkTypes []NetworkType
- // CandidateTypes is an optional configuration for disabling or enabling
- // support for specific candidate types.
- CandidateTypes []CandidateType
- LoggerFactory logging.LoggerFactory
- // MaxBindingRequests is the max amount of binding requests the agent will send
- // over a candidate pair for validation or nomination, if after MaxBindingRequests
- // the candidate is yet to answer a binding request or a nomination we set the pair as failed
- MaxBindingRequests *uint16
- // Lite agents do not perform connectivity check and only provide host candidates.
- Lite bool
- // NAT1To1IPCandidateType is used along with NAT1To1IPs to specify which candidate type
- // the 1:1 NAT IP addresses should be mapped to.
- // If unspecified or CandidateTypeHost, NAT1To1IPs are used to replace host candidate IPs.
- // If CandidateTypeServerReflexive, it will insert a srflx candidate (as if it was derived
- // from a STUN server) with its port number being the one for the actual host candidate.
- // Other values will result in an error.
- NAT1To1IPCandidateType CandidateType
- // NAT1To1IPs contains a list of public IP addresses that are to be used as a host
- // candidate or srflx candidate. This is used typically for servers that are behind
- // 1:1 D-NAT (e.g. AWS EC2 instances) and to eliminate the need of server reflexive
- // candidate gathering.
- NAT1To1IPs []string
- // HostAcceptanceMinWait specify a minimum wait time before selecting host candidates
- HostAcceptanceMinWait *time.Duration
- // HostAcceptanceMinWait specify a minimum wait time before selecting srflx candidates
- SrflxAcceptanceMinWait *time.Duration
- // HostAcceptanceMinWait specify a minimum wait time before selecting prflx candidates
- PrflxAcceptanceMinWait *time.Duration
- // HostAcceptanceMinWait specify a minimum wait time before selecting relay candidates
- RelayAcceptanceMinWait *time.Duration
- // Net is the our abstracted network interface for internal development purpose only
- // (see https://github.com/pion/transport)
- Net transport.Net
- // InterfaceFilter is a function that you can use in order to whitelist or blacklist
- // the interfaces which are used to gather ICE candidates.
- InterfaceFilter func(string) bool
- // IPFilter is a function that you can use in order to whitelist or blacklist
- // the ips which are used to gather ICE candidates.
- IPFilter func(net.IP) bool
- // InsecureSkipVerify controls if self-signed certificates are accepted when connecting
- // to TURN servers via TLS or DTLS
- InsecureSkipVerify bool
- // TCPMux will be used for multiplexing incoming TCP connections for ICE TCP.
- // Currently only passive candidates are supported. This functionality is
- // experimental and the API might change in the future.
- TCPMux TCPMux
- // UDPMux is used for multiplexing multiple incoming UDP connections on a single port
- // when this is set, the agent ignores PortMin and PortMax configurations and will
- // defer to UDPMux for incoming connections
- UDPMux UDPMux
- // UDPMuxSrflx is used for multiplexing multiple incoming UDP connections of server reflexive candidates
- // on a single port when this is set, the agent ignores PortMin and PortMax configurations and will
- // defer to UDPMuxSrflx for incoming connections
- // It embeds UDPMux to do the actual connection multiplexing
- UDPMuxSrflx UniversalUDPMux
- // Proxy Dialer is a dialer that should be implemented by the user based on golang.org/x/net/proxy
- // dial interface in order to support corporate proxies
- ProxyDialer proxy.Dialer
- // Deprecated: AcceptAggressiveNomination always enabled.
- AcceptAggressiveNomination bool
- // Include loopback addresses in the candidate list.
- IncludeLoopback bool
- // TCPPriorityOffset is a number which is subtracted from the default (UDP) candidate type preference
- // for host, srflx and prfx candidate types. It helps to configure relative preference of UDP candidates
- // against TCP ones. Relay candidates for TCP and UDP are always 0 and not affected by this setting.
- // When this is nil, defaultTCPPriorityOffset is used.
- TCPPriorityOffset *uint16
- // DisableActiveTCP can be used to disable Active TCP candidates. Otherwise when TCP is enabled
- // Active TCP candidates will be created when a new passive TCP remote candidate is added.
- DisableActiveTCP bool
- // BindingRequestHandler allows applications to perform logic on incoming STUN Binding Requests
- // This was implemented to allow users to
- // * Log incoming Binding Requests for debugging
- // * Implement draft-thatcher-ice-renomination
- // * Implement custom CandidatePair switching logic
- BindingRequestHandler func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool
- }
- // initWithDefaults populates an agent and falls back to defaults if fields are unset
- func (config *AgentConfig) initWithDefaults(a *Agent) {
- if config.MaxBindingRequests == nil {
- a.maxBindingRequests = defaultMaxBindingRequests
- } else {
- a.maxBindingRequests = *config.MaxBindingRequests
- }
- if config.HostAcceptanceMinWait == nil {
- a.hostAcceptanceMinWait = defaultHostAcceptanceMinWait
- } else {
- a.hostAcceptanceMinWait = *config.HostAcceptanceMinWait
- }
- if config.SrflxAcceptanceMinWait == nil {
- a.srflxAcceptanceMinWait = defaultSrflxAcceptanceMinWait
- } else {
- a.srflxAcceptanceMinWait = *config.SrflxAcceptanceMinWait
- }
- if config.PrflxAcceptanceMinWait == nil {
- a.prflxAcceptanceMinWait = defaultPrflxAcceptanceMinWait
- } else {
- a.prflxAcceptanceMinWait = *config.PrflxAcceptanceMinWait
- }
- if config.RelayAcceptanceMinWait == nil {
- a.relayAcceptanceMinWait = defaultRelayAcceptanceMinWait
- } else {
- a.relayAcceptanceMinWait = *config.RelayAcceptanceMinWait
- }
- if config.TCPPriorityOffset == nil {
- a.tcpPriorityOffset = defaultTCPPriorityOffset
- } else {
- a.tcpPriorityOffset = *config.TCPPriorityOffset
- }
- if config.DisconnectedTimeout == nil {
- a.disconnectedTimeout = defaultDisconnectedTimeout
- } else {
- a.disconnectedTimeout = *config.DisconnectedTimeout
- }
- if config.FailedTimeout == nil {
- a.failedTimeout = defaultFailedTimeout
- } else {
- a.failedTimeout = *config.FailedTimeout
- }
- if config.KeepaliveInterval == nil {
- a.keepaliveInterval = defaultKeepaliveInterval
- } else {
- a.keepaliveInterval = *config.KeepaliveInterval
- }
- if config.CheckInterval == nil {
- a.checkInterval = defaultCheckInterval
- } else {
- a.checkInterval = *config.CheckInterval
- }
- if config.CandidateTypes == nil || len(config.CandidateTypes) == 0 {
- a.candidateTypes = defaultCandidateTypes()
- } else {
- a.candidateTypes = config.CandidateTypes
- }
- }
- func (config *AgentConfig) initExtIPMapping(a *Agent) error {
- var err error
- a.extIPMapper, err = newExternalIPMapper(config.NAT1To1IPCandidateType, config.NAT1To1IPs)
- if err != nil {
- return err
- }
- if a.extIPMapper == nil {
- return nil // This may happen when config.NAT1To1IPs is an empty array
- }
- if a.extIPMapper.candidateType == CandidateTypeHost {
- if a.mDNSMode == MulticastDNSModeQueryAndGather {
- return ErrMulticastDNSWithNAT1To1IPMapping
- }
- candiHostEnabled := false
- for _, candiType := range a.candidateTypes {
- if candiType == CandidateTypeHost {
- candiHostEnabled = true
- break
- }
- }
- if !candiHostEnabled {
- return ErrIneffectiveNAT1To1IPMappingHost
- }
- } else if a.extIPMapper.candidateType == CandidateTypeServerReflexive {
- candiSrflxEnabled := false
- for _, candiType := range a.candidateTypes {
- if candiType == CandidateTypeServerReflexive {
- candiSrflxEnabled = true
- break
- }
- }
- if !candiSrflxEnabled {
- return ErrIneffectiveNAT1To1IPMappingSrflx
- }
- }
- return nil
- }
|