forked from ccding/go-stun
/
attribute.go
90 lines (78 loc) · 2.4 KB
/
attribute.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2013, Cong Ding. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: Cong Ding <dinggnu@gmail.com>
package stun
import (
"encoding/binary"
"hash/crc32"
"net"
)
type attribute struct {
types uint16
length uint16
value []byte
}
func newAttribute(types uint16, value []byte) *attribute {
a := new(attribute)
a.types = types
a.value = padding(value)
a.length = uint16(len(a.value))
return a
}
func newFingerprintAttribute(packet *packet) *attribute {
crc := crc32.ChecksumIEEE(packet.bytes()) ^ fingerprint
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, crc)
return newAttribute(attribute_fingerprint, buf)
}
func newSoftwareAttribute(packet *packet, name string) *attribute {
return newAttribute(attribute_SOFTWARE, []byte(name))
}
func newChangeReqAttribute(packet *packet, changeIp bool, changePort bool) *attribute {
value := make([]byte, 4)
if changeIp {
value[3] |= 0x04
}
if changePort {
value[3] |= 0x02
}
return newAttribute(attribute_CHANGE_REQUEST, value)
}
func (v *attribute) xorMappedAddr() *Host {
cookie := make([]byte, 4)
binary.BigEndian.PutUint32(cookie, magicCookie)
xorIp := make([]byte, 16)
for i := 0; i < len(v.value)-4; i++ {
xorIp[i] = v.value[i+4] ^ cookie[i]
}
family := binary.BigEndian.Uint16(v.value[0:2])
port := binary.BigEndian.Uint16(v.value[2:4])
// Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address.
if family == attribute_FAMILY_IPV4 {
xorIp = xorIp[:4]
}
return &Host{family, net.IP(xorIp).String(), port ^ (magicCookie >> 32)}
}
func (v *attribute) address() *Host {
h := new(Host)
h.family = binary.BigEndian.Uint16(v.value[0:2])
h.port = binary.BigEndian.Uint16(v.value[2:4])
// Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address.
if h.family == attribute_FAMILY_IPV4 {
v.value = v.value[:8]
}
h.ip = net.IP(v.value[4:]).String()
return h
}