blob: 2f6a5a7ccfef34e465db962c77c22182493c8c8f [file] [log] [blame]
Scott Baker8461e152019-10-01 14:44:30 -07001package types
2
3// Reference: https://www.ietf.org/rfc/rfc4120.txt
4// Section: 5.2.5
5
6import (
7 "bytes"
8 "fmt"
9 "net"
10
11 "github.com/jcmturner/gofork/encoding/asn1"
12 "gopkg.in/jcmturner/gokrb5.v7/iana/addrtype"
13)
14
15/*
16HostAddress and HostAddresses
17
18HostAddress ::= SEQUENCE {
19 addr-type [0] Int32,
20 address [1] OCTET STRING
21}
22
23-- NOTE: HostAddresses is always used as an OPTIONAL field and
24-- should not be empty.
25HostAddresses -- NOTE: subtly different from rfc1510,
26 -- but has a value mapping and encodes the same
27 ::= SEQUENCE OF HostAddress
28
29The host address encodings consist of two fields:
30
31addr-type
32 This field specifies the type of address that follows. Pre-
33 defined values for this field are specified in Section 7.5.3.
34
35address
36 This field encodes a single address of type addr-type.
37*/
38
39// HostAddresses implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
40type HostAddresses []HostAddress
41
42// HostAddress implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
43type HostAddress struct {
44 AddrType int32 `asn1:"explicit,tag:0"`
45 Address []byte `asn1:"explicit,tag:1"`
46}
47
48// GetHostAddress returns a HostAddress struct from a string in the format <hostname>:<port>
49func GetHostAddress(s string) (HostAddress, error) {
50 var h HostAddress
51 cAddr, _, err := net.SplitHostPort(s)
52 if err != nil {
53 return h, fmt.Errorf("invalid format of client address: %v", err)
54 }
55 ip := net.ParseIP(cAddr)
56 var ht int32
57 if ip.To4() != nil {
58 ht = addrtype.IPv4
59 ip = ip.To4()
60 } else if ip.To16() != nil {
61 ht = addrtype.IPv6
62 ip = ip.To16()
63 } else {
64 return h, fmt.Errorf("could not determine client's address types: %v", err)
65 }
66 h = HostAddress{
67 AddrType: ht,
68 Address: ip,
69 }
70 return h, nil
71}
72
73// GetAddress returns a string representation of the HostAddress.
74func (h *HostAddress) GetAddress() (string, error) {
75 var b []byte
76 _, err := asn1.Unmarshal(h.Address, &b)
77 return string(b), err
78}
79
80// LocalHostAddresses returns a HostAddresses struct for the local machines interface IP addresses.
81func LocalHostAddresses() (ha HostAddresses, err error) {
82 ifs, err := net.Interfaces()
83 if err != nil {
84 return
85 }
86 for _, iface := range ifs {
87 if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
88 // Interface is either loopback of not up
89 continue
90 }
91 addrs, err := iface.Addrs()
92 if err != nil {
93 continue
94 }
95 for _, addr := range addrs {
96 var ip net.IP
97 switch v := addr.(type) {
98 case *net.IPNet:
99 ip = v.IP
100 case *net.IPAddr:
101 ip = v.IP
102 }
103 var a HostAddress
104 if ip.To16() == nil {
105 //neither IPv4 or IPv6
106 continue
107 }
108 if ip.To4() != nil {
109 //Is IPv4
110 a.AddrType = addrtype.IPv4
111 a.Address = ip.To4()
112 } else {
113 a.AddrType = addrtype.IPv6
114 a.Address = ip.To16()
115 }
116 ha = append(ha, a)
117 }
118 }
119 return ha, nil
120}
121
122// HostAddressesFromNetIPs returns a HostAddresses type from a slice of net.IP
123func HostAddressesFromNetIPs(ips []net.IP) (ha HostAddresses) {
124 for _, ip := range ips {
125 ha = append(ha, HostAddressFromNetIP(ip))
126 }
127 return ha
128}
129
130// HostAddressFromNetIP returns a HostAddress type from a net.IP
131func HostAddressFromNetIP(ip net.IP) HostAddress {
132 if ip.To4() != nil {
133 //Is IPv4
134 return HostAddress{
135 AddrType: addrtype.IPv4,
136 Address: ip.To4(),
137 }
138 }
139 return HostAddress{
140 AddrType: addrtype.IPv6,
141 Address: ip.To16(),
142 }
143}
144
145// HostAddressesEqual tests if two HostAddress slices are equal.
146func HostAddressesEqual(h, a []HostAddress) bool {
147 if len(h) != len(a) {
148 return false
149 }
150 for _, e := range a {
151 var found bool
152 for _, i := range h {
153 if e.Equal(i) {
154 found = true
155 break
156 }
157 }
158 if !found {
159 return false
160 }
161 }
162 return true
163}
164
165// HostAddressesContains tests if a HostAddress is contained in a HostAddress slice.
166func HostAddressesContains(h []HostAddress, a HostAddress) bool {
167 for _, e := range h {
168 if e.Equal(a) {
169 return true
170 }
171 }
172 return false
173}
174
175// Equal tests if the HostAddress is equal to another HostAddress provided.
176func (h *HostAddress) Equal(a HostAddress) bool {
177 if h.AddrType != a.AddrType {
178 return false
179 }
180 return bytes.Equal(h.Address, a.Address)
181}
182
183// Contains tests if a HostAddress is contained within the HostAddresses struct.
184func (h *HostAddresses) Contains(a HostAddress) bool {
185 for _, e := range *h {
186 if e.Equal(a) {
187 return true
188 }
189 }
190 return false
191}
192
193// Equal tests if a HostAddress slice is equal to the HostAddresses struct.
194func (h *HostAddresses) Equal(a []HostAddress) bool {
195 if len(*h) != len(a) {
196 return false
197 }
198 for _, e := range a {
199 if !h.Contains(e) {
200 return false
201 }
202 }
203 return true
204}