blob: 895fe80539182cbae551459fa4cabb625815a8de [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001package 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 "github.com/jcmturner/gokrb5/v8/iana/addrtype"
13)
14
15// HostAddresses implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
16type HostAddresses []HostAddress
17
18// HostAddress implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
19type HostAddress struct {
20 AddrType int32 `asn1:"explicit,tag:0"`
21 Address []byte `asn1:"explicit,tag:1"`
22}
23
24// GetHostAddress returns a HostAddress struct from a string in the format <hostname>:<port>
25func GetHostAddress(s string) (HostAddress, error) {
26 var h HostAddress
27 cAddr, _, err := net.SplitHostPort(s)
28 if err != nil {
29 return h, fmt.Errorf("invalid format of client address: %v", err)
30 }
31 ip := net.ParseIP(cAddr)
32 var ht int32
33 if ip.To4() != nil {
34 ht = addrtype.IPv4
35 ip = ip.To4()
36 } else if ip.To16() != nil {
37 ht = addrtype.IPv6
38 ip = ip.To16()
39 } else {
40 return h, fmt.Errorf("could not determine client's address types: %v", err)
41 }
42 h = HostAddress{
43 AddrType: ht,
44 Address: ip,
45 }
46 return h, nil
47}
48
49// GetAddress returns a string representation of the HostAddress.
50func (h *HostAddress) GetAddress() (string, error) {
51 var b []byte
52 _, err := asn1.Unmarshal(h.Address, &b)
53 return string(b), err
54}
55
56// LocalHostAddresses returns a HostAddresses struct for the local machines interface IP addresses.
57func LocalHostAddresses() (ha HostAddresses, err error) {
58 ifs, err := net.Interfaces()
59 if err != nil {
60 return
61 }
62 for _, iface := range ifs {
63 if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
64 // Interface is either loopback of not up
65 continue
66 }
67 addrs, err := iface.Addrs()
68 if err != nil {
69 continue
70 }
71 for _, addr := range addrs {
72 var ip net.IP
73 switch v := addr.(type) {
74 case *net.IPNet:
75 ip = v.IP
76 case *net.IPAddr:
77 ip = v.IP
78 }
79 var a HostAddress
80 if ip.To16() == nil {
81 //neither IPv4 or IPv6
82 continue
83 }
84 if ip.To4() != nil {
85 //Is IPv4
86 a.AddrType = addrtype.IPv4
87 a.Address = ip.To4()
88 } else {
89 a.AddrType = addrtype.IPv6
90 a.Address = ip.To16()
91 }
92 ha = append(ha, a)
93 }
94 }
95 return ha, nil
96}
97
98// HostAddressesFromNetIPs returns a HostAddresses type from a slice of net.IP
99func HostAddressesFromNetIPs(ips []net.IP) (ha HostAddresses) {
100 for _, ip := range ips {
101 ha = append(ha, HostAddressFromNetIP(ip))
102 }
103 return ha
104}
105
106// HostAddressFromNetIP returns a HostAddress type from a net.IP
107func HostAddressFromNetIP(ip net.IP) HostAddress {
108 if ip.To4() != nil {
109 //Is IPv4
110 return HostAddress{
111 AddrType: addrtype.IPv4,
112 Address: ip.To4(),
113 }
114 }
115 return HostAddress{
116 AddrType: addrtype.IPv6,
117 Address: ip.To16(),
118 }
119}
120
121// HostAddressesEqual tests if two HostAddress slices are equal.
122func HostAddressesEqual(h, a []HostAddress) bool {
123 if len(h) != len(a) {
124 return false
125 }
126 for _, e := range a {
127 var found bool
128 for _, i := range h {
129 if e.Equal(i) {
130 found = true
131 break
132 }
133 }
134 if !found {
135 return false
136 }
137 }
138 return true
139}
140
141// HostAddressesContains tests if a HostAddress is contained in a HostAddress slice.
142func HostAddressesContains(h []HostAddress, a HostAddress) bool {
143 for _, e := range h {
144 if e.Equal(a) {
145 return true
146 }
147 }
148 return false
149}
150
151// Equal tests if the HostAddress is equal to another HostAddress provided.
152func (h *HostAddress) Equal(a HostAddress) bool {
153 if h.AddrType != a.AddrType {
154 return false
155 }
156 return bytes.Equal(h.Address, a.Address)
157}
158
159// Contains tests if a HostAddress is contained within the HostAddresses struct.
160func (h *HostAddresses) Contains(a HostAddress) bool {
161 for _, e := range *h {
162 if e.Equal(a) {
163 return true
164 }
165 }
166 return false
167}
168
169// Equal tests if a HostAddress slice is equal to the HostAddresses struct.
170func (h *HostAddresses) Equal(a []HostAddress) bool {
171 if len(*h) != len(a) {
172 return false
173 }
174 for _, e := range a {
175 if !h.Contains(e) {
176 return false
177 }
178 }
179 return true
180}