1package stun 2 3import ( 4 "fmt" 5 "io" 6 "net" 7 "strconv" 8) 9 10// MappedAddress represents MAPPED-ADDRESS attribute. 11// 12// This attribute is used only by servers for achieving backwards 13// compatibility with RFC 3489 clients. 14// 15// RFC 5389 Section 15.1 16type MappedAddress struct { 17 IP net.IP 18 Port int 19} 20 21// AlternateServer represents ALTERNATE-SERVER attribute. 22// 23// RFC 5389 Section 15.11 24type AlternateServer struct { 25 IP net.IP 26 Port int 27} 28 29// OtherAddress represents OTHER-ADDRESS attribute. 30// 31// RFC 5780 Section 7.4 32type OtherAddress struct { 33 IP net.IP 34 Port int 35} 36 37// AddTo adds ALTERNATE-SERVER attribute to message. 38func (s *AlternateServer) AddTo(m *Message) error { 39 a := (*MappedAddress)(s) 40 return a.addAs(m, AttrAlternateServer) 41} 42 43// GetFrom decodes ALTERNATE-SERVER from message. 44func (s *AlternateServer) GetFrom(m *Message) error { 45 a := (*MappedAddress)(s) 46 return a.getAs(m, AttrAlternateServer) 47} 48 49func (a MappedAddress) String() string { 50 return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port)) 51} 52 53func (a *MappedAddress) getAs(m *Message, t AttrType) error { 54 v, err := m.Get(t) 55 if err != nil { 56 return err 57 } 58 if len(v) <= 4 { 59 return io.ErrUnexpectedEOF 60 } 61 family := bin.Uint16(v[0:2]) 62 if family != familyIPv6 && family != familyIPv4 { 63 return newDecodeErr("xor-mapped address", "family", 64 fmt.Sprintf("bad value %d", family), 65 ) 66 } 67 ipLen := net.IPv4len 68 if family == familyIPv6 { 69 ipLen = net.IPv6len 70 } 71 // Ensuring len(a.IP) == ipLen and reusing a.IP. 72 if len(a.IP) < ipLen { 73 a.IP = a.IP[:cap(a.IP)] 74 for len(a.IP) < ipLen { 75 a.IP = append(a.IP, 0) 76 } 77 } 78 a.IP = a.IP[:ipLen] 79 for i := range a.IP { 80 a.IP[i] = 0 81 } 82 a.Port = int(bin.Uint16(v[2:4])) 83 copy(a.IP, v[4:]) 84 return nil 85} 86 87func (a *MappedAddress) addAs(m *Message, t AttrType) error { 88 var ( 89 family = familyIPv4 90 ip = a.IP 91 ) 92 if len(a.IP) == net.IPv6len { 93 if isIPv4(ip) { 94 ip = ip[12:16] // like in ip.To4() 95 } else { 96 family = familyIPv6 97 } 98 } else if len(ip) != net.IPv4len { 99 return ErrBadIPLength 100 } 101 value := make([]byte, 128) 102 value[0] = 0 // first 8 bits are zeroes 103 bin.PutUint16(value[0:2], family) 104 bin.PutUint16(value[2:4], uint16(a.Port)) 105 copy(value[4:], ip) 106 m.Add(t, value[:4+len(ip)]) 107 return nil 108} 109 110// AddTo adds MAPPED-ADDRESS to message. 111func (a *MappedAddress) AddTo(m *Message) error { 112 return a.addAs(m, AttrMappedAddress) 113} 114 115// GetFrom decodes MAPPED-ADDRESS from message. 116func (a *MappedAddress) GetFrom(m *Message) error { 117 return a.getAs(m, AttrMappedAddress) 118} 119 120// AddTo adds OTHER-ADDRESS attribute to message. 121func (o *OtherAddress) AddTo(m *Message) error { 122 a := (*MappedAddress)(o) 123 return a.addAs(m, AttrOtherAddress) 124} 125 126// GetFrom decodes OTHER-ADDRESS from message. 127func (o *OtherAddress) GetFrom(m *Message) error { 128 a := (*MappedAddress)(o) 129 return a.getAs(m, AttrOtherAddress) 130} 131 132func (o OtherAddress) String() string { 133 return net.JoinHostPort(o.IP.String(), strconv.Itoa(o.Port)) 134} 135