| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- package ice
- import (
- "fmt"
- "net"
- "sync/atomic"
- "time"
- "github.com/pion/logging"
- "github.com/pion/stun"
- "github.com/pion/transport/vnet"
- )
- type atomicError struct{ v atomic.Value }
- func (a *atomicError) Store(err error) {
- a.v.Store(struct{ error }{err})
- }
- func (a *atomicError) Load() error {
- err, _ := a.v.Load().(struct{ error })
- return err.error
- }
- // The conditions of invalidation written below are defined in
- // https://tools.ietf.org/html/rfc8445#section-5.1.1.1
- func isSupportedIPv6(ip net.IP) bool {
- if len(ip) != net.IPv6len ||
- isZeros(ip[0:12]) || // !(IPv4-compatible IPv6)
- ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 || // !(IPv6 site-local unicast)
- ip.IsLinkLocalUnicast() ||
- ip.IsLinkLocalMulticast() {
- return false
- }
- return true
- }
- func isZeros(ip net.IP) bool {
- for i := 0; i < len(ip); i++ {
- if ip[i] != 0 {
- return false
- }
- }
- return true
- }
- func parseAddr(in net.Addr) (net.IP, int, NetworkType, bool) {
- switch addr := in.(type) {
- case *net.UDPAddr:
- return addr.IP, addr.Port, NetworkTypeUDP4, true
- case *net.TCPAddr:
- return addr.IP, addr.Port, NetworkTypeTCP4, true
- }
- return nil, 0, 0, false
- }
- func createAddr(network NetworkType, ip net.IP, port int) net.Addr {
- switch {
- case network.IsTCP():
- return &net.TCPAddr{IP: ip, Port: port}
- default:
- return &net.UDPAddr{IP: ip, Port: port}
- }
- }
- func addrEqual(a, b net.Addr) bool {
- aIP, aPort, aType, aOk := parseAddr(a)
- if !aOk {
- return false
- }
- bIP, bPort, bType, bOk := parseAddr(b)
- if !bOk {
- return false
- }
- return aType == bType && aIP.Equal(bIP) && aPort == bPort
- }
- // getXORMappedAddr initiates a stun requests to serverAddr using conn, reads the response and returns
- // the XORMappedAddress returned by the stun server.
- //
- // Adapted from stun v0.2.
- func getXORMappedAddr(conn net.PacketConn, serverAddr net.Addr, deadline time.Duration) (*stun.XORMappedAddress, error) {
- if deadline > 0 {
- if err := conn.SetReadDeadline(time.Now().Add(deadline)); err != nil {
- return nil, err
- }
- }
- defer func() {
- if deadline > 0 {
- _ = conn.SetReadDeadline(time.Time{})
- }
- }()
- resp, err := stunRequest(
- func(p []byte) (int, error) {
- n, _, errr := conn.ReadFrom(p)
- return n, errr
- },
- func(b []byte) (int, error) {
- return conn.WriteTo(b, serverAddr)
- },
- )
- if err != nil {
- return nil, err
- }
- var addr stun.XORMappedAddress
- if err = addr.GetFrom(resp); err != nil {
- return nil, fmt.Errorf("%w: %v", errGetXorMappedAddrResponse, err)
- }
- return &addr, nil
- }
- func stunRequest(read func([]byte) (int, error), write func([]byte) (int, error)) (*stun.Message, error) {
- req, err := stun.Build(stun.BindingRequest, stun.TransactionID)
- if err != nil {
- return nil, err
- }
- if _, err = write(req.Raw); err != nil {
- return nil, err
- }
- const maxMessageSize = 1280
- bs := make([]byte, maxMessageSize)
- n, err := read(bs)
- if err != nil {
- return nil, err
- }
- res := &stun.Message{Raw: bs[:n]}
- if err := res.Decode(); err != nil {
- return nil, err
- }
- return res, nil
- }
- func localInterfaces(vnet *vnet.Net, interfaceFilter func(string) bool, networkTypes []NetworkType) ([]net.IP, error) { //nolint:gocognit
- ips := []net.IP{}
- ifaces, err := vnet.Interfaces()
- if err != nil {
- return ips, err
- }
- var IPv4Requested, IPv6Requested bool
- for _, typ := range networkTypes {
- if typ.IsIPv4() {
- IPv4Requested = true
- }
- if typ.IsIPv6() {
- IPv6Requested = true
- }
- }
- for _, iface := range ifaces {
- if iface.Flags&net.FlagUp == 0 {
- continue // interface down
- }
- if iface.Flags&net.FlagLoopback != 0 {
- continue // loopback interface
- }
- if interfaceFilter != nil && !interfaceFilter(iface.Name) {
- continue
- }
- addrs, err := iface.Addrs()
- if err != nil {
- continue
- }
- for _, addr := range addrs {
- var ip net.IP
- switch addr := addr.(type) {
- case *net.IPNet:
- ip = addr.IP
- case *net.IPAddr:
- ip = addr.IP
- }
- if ip == nil || ip.IsLoopback() {
- continue
- }
- if ipv4 := ip.To4(); ipv4 == nil {
- if !IPv6Requested {
- continue
- } else if !isSupportedIPv6(ip) {
- continue
- }
- } else if !IPv4Requested {
- continue
- }
- ips = append(ips, ip)
- }
- }
- return ips, nil
- }
- func listenUDPInPortRange(vnet *vnet.Net, log logging.LeveledLogger, portMax, portMin int, network string, laddr *net.UDPAddr) (vnet.UDPPacketConn, error) {
- if (laddr.Port != 0) || ((portMin == 0) && (portMax == 0)) {
- return vnet.ListenUDP(network, laddr)
- }
- var i, j int
- i = portMin
- if i == 0 {
- i = 1
- }
- j = portMax
- if j == 0 {
- j = 0xFFFF
- }
- if i > j {
- return nil, ErrPort
- }
- portStart := globalMathRandomGenerator.Intn(j-i+1) + i
- portCurrent := portStart
- for {
- laddr = &net.UDPAddr{IP: laddr.IP, Port: portCurrent}
- c, e := vnet.ListenUDP(network, laddr)
- if e == nil {
- return c, e
- }
- log.Debugf("failed to listen %s: %v", laddr.String(), e)
- portCurrent++
- if portCurrent > j {
- portCurrent = i
- }
- if portCurrent == portStart {
- break
- }
- }
- return nil, ErrPort
- }
|