package stun
import (
"errors"
"fmt"
"io"
"net"
"strconv"
"github.com/pion/transport/v2/utils/xor"
)
const (
familyIPv4 uint16 = 0x01
familyIPv6 uint16 = 0x02
)
type XORMappedAddress struct {
IP net .IP
Port int
}
func (a XORMappedAddress ) String () string {
return net .JoinHostPort (a .IP .String (), strconv .Itoa (a .Port ))
}
func isIPv4(ip net .IP ) bool {
return isZeros (ip [0 :10 ]) && ip [10 ] == 0xff && ip [11 ] == 0xff
}
func isZeros(p net .IP ) bool {
for i := 0 ; i < len (p ); i ++ {
if p [i ] != 0 {
return false
}
}
return true
}
var ErrBadIPLength = errors .New ("invalid length of IP value" )
func (a XORMappedAddress ) AddToAs (m *Message , t AttrType ) error {
var (
family = familyIPv4
ip = a .IP
)
if len (a .IP ) == net .IPv6len {
if isIPv4 (ip ) {
ip = ip [12 :16 ]
} else {
family = familyIPv6
}
} else if len (ip ) != net .IPv4len {
return ErrBadIPLength
}
value := make ([]byte , 32 +128 )
value [0 ] = 0
xorValue := make ([]byte , net .IPv6len )
copy (xorValue [4 :], m .TransactionID [:])
bin .PutUint32 (xorValue [0 :4 ], magicCookie )
bin .PutUint16 (value [0 :2 ], family )
bin .PutUint16 (value [2 :4 ], uint16 (a .Port ^magicCookie >>16 ))
xor .XorBytes (value [4 :4 +len (ip )], ip , xorValue )
m .Add (t , value [:4 +len (ip )])
return nil
}
func (a XORMappedAddress ) AddTo (m *Message ) error {
return a .AddToAs (m , AttrXORMappedAddress )
}
func (a *XORMappedAddress ) GetFromAs (m *Message , t AttrType ) error {
v , err := m .Get (t )
if err != nil {
return err
}
family := bin .Uint16 (v [0 :2 ])
if family != familyIPv6 && family != familyIPv4 {
return newDecodeErr ("xor-mapped address" , "family" ,
fmt .Sprintf ("bad value %d" , family ),
)
}
ipLen := net .IPv4len
if family == familyIPv6 {
ipLen = net .IPv6len
}
if len (a .IP ) < ipLen {
a .IP = a .IP [:cap (a .IP )]
for len (a .IP ) < ipLen {
a .IP = append (a .IP , 0 )
}
}
a .IP = a .IP [:ipLen ]
for i := range a .IP {
a .IP [i ] = 0
}
if len (v ) <= 4 {
return io .ErrUnexpectedEOF
}
if err := CheckOverflow (t , len (v [4 :]), len (a .IP )); err != nil {
return err
}
a .Port = int (bin .Uint16 (v [2 :4 ])) ^ (magicCookie >> 16 )
xorValue := make ([]byte , 4 +TransactionIDSize )
bin .PutUint32 (xorValue [0 :4 ], magicCookie )
copy (xorValue [4 :], m .TransactionID [:])
xor .XorBytes (a .IP , v [4 :], xorValue )
return nil
}
func (a *XORMappedAddress ) GetFrom (m *Message ) error {
return a .GetFromAs (m , AttrXORMappedAddress )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .