diff options
Diffstat (limited to 'vendor/github.com/pion/stun/xoraddr.go')
-rw-r--r-- | vendor/github.com/pion/stun/xoraddr.go | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/vendor/github.com/pion/stun/xoraddr.go b/vendor/github.com/pion/stun/xoraddr.go new file mode 100644 index 0000000..23f7777 --- /dev/null +++ b/vendor/github.com/pion/stun/xoraddr.go @@ -0,0 +1,145 @@ +package stun + +import ( + "errors" + "fmt" + "io" + "net" + "strconv" +) + +const ( + familyIPv4 uint16 = 0x01 + familyIPv6 uint16 = 0x02 +) + +// XORMappedAddress implements XOR-MAPPED-ADDRESS attribute. +// +// RFC 5389 Section 15.2 +type XORMappedAddress struct { + IP net.IP + Port int +} + +func (a XORMappedAddress) String() string { + return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port)) +} + +// isIPv4 returns true if ip with len of net.IPv6Len seems to be ipv4. +func isIPv4(ip net.IP) bool { + // Optimized for performance. Copied from net.IP.To4. + return isZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff +} + +// Is p all zeros? +func isZeros(p net.IP) bool { + for i := 0; i < len(p); i++ { + if p[i] != 0 { + return false + } + } + return true +} + +// ErrBadIPLength means that len(IP) is not net.{IPv6len,IPv4len}. +var ErrBadIPLength = errors.New("invalid length of IP value") + +// AddToAs adds XOR-MAPPED-ADDRESS value to m as t attribute. +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] // like in ip.To4() + } else { + family = familyIPv6 + } + } else if len(ip) != net.IPv4len { + return ErrBadIPLength + } + value := make([]byte, 32+128) + value[0] = 0 // first 8 bits are zeroes + 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)) + xorBytes(value[4:4+len(ip)], ip, xorValue) + m.Add(t, value[:4+len(ip)]) + return nil +} + +// AddTo adds XOR-MAPPED-ADDRESS to m. Can return ErrBadIPLength +// if len(a.IP) is invalid. +func (a XORMappedAddress) AddTo(m *Message) error { + return a.AddToAs(m, AttrXORMappedAddress) +} + +// GetFromAs decodes XOR-MAPPED-ADDRESS attribute value in message +// getting it as for t type. +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 + } + // Ensuring len(a.IP) == ipLen and reusing a.IP. + 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[:]) + xorBytes(a.IP, v[4:], xorValue) + return nil +} + +// GetFrom decodes XOR-MAPPED-ADDRESS attribute in message and returns +// error if any. While decoding, a.IP is reused if possible and can be +// rendered to invalid state (e.g. if a.IP was set to IPv6 and then +// IPv4 value were decoded into it), be careful. +// +// Example: +// +// expectedIP := net.ParseIP("213.141.156.236") +// expectedIP.String() // 213.141.156.236, 16 bytes, first 12 of them are zeroes +// expectedPort := 21254 +// addr := &XORMappedAddress{ +// IP: expectedIP, +// Port: expectedPort, +// } +// // addr were added to message that is decoded as newMessage +// // ... +// +// addr.GetFrom(newMessage) +// addr.IP.String() // 213.141.156.236, net.IPv4Len +// expectedIP.String() // d58d:9cec::ffff:d58d:9cec, 16 bytes, first 4 are IPv4 +// // now we have len(expectedIP) = 16 and len(addr.IP) = 4. +func (a *XORMappedAddress) GetFrom(m *Message) error { + return a.GetFromAs(m, AttrXORMappedAddress) +} |