blob: 2f6a5a7ccfef34e465db962c77c22182493c8c8f [file] [log] [blame]
package types
// Reference: https://www.ietf.org/rfc/rfc4120.txt
// Section: 5.2.5
import (
"bytes"
"fmt"
"net"
"github.com/jcmturner/gofork/encoding/asn1"
"gopkg.in/jcmturner/gokrb5.v7/iana/addrtype"
)
/*
HostAddress and HostAddresses
HostAddress ::= SEQUENCE {
addr-type [0] Int32,
address [1] OCTET STRING
}
-- NOTE: HostAddresses is always used as an OPTIONAL field and
-- should not be empty.
HostAddresses -- NOTE: subtly different from rfc1510,
-- but has a value mapping and encodes the same
::= SEQUENCE OF HostAddress
The host address encodings consist of two fields:
addr-type
This field specifies the type of address that follows. Pre-
defined values for this field are specified in Section 7.5.3.
address
This field encodes a single address of type addr-type.
*/
// HostAddresses implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
type HostAddresses []HostAddress
// HostAddress implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.2.5
type HostAddress struct {
AddrType int32 `asn1:"explicit,tag:0"`
Address []byte `asn1:"explicit,tag:1"`
}
// GetHostAddress returns a HostAddress struct from a string in the format <hostname>:<port>
func GetHostAddress(s string) (HostAddress, error) {
var h HostAddress
cAddr, _, err := net.SplitHostPort(s)
if err != nil {
return h, fmt.Errorf("invalid format of client address: %v", err)
}
ip := net.ParseIP(cAddr)
var ht int32
if ip.To4() != nil {
ht = addrtype.IPv4
ip = ip.To4()
} else if ip.To16() != nil {
ht = addrtype.IPv6
ip = ip.To16()
} else {
return h, fmt.Errorf("could not determine client's address types: %v", err)
}
h = HostAddress{
AddrType: ht,
Address: ip,
}
return h, nil
}
// GetAddress returns a string representation of the HostAddress.
func (h *HostAddress) GetAddress() (string, error) {
var b []byte
_, err := asn1.Unmarshal(h.Address, &b)
return string(b), err
}
// LocalHostAddresses returns a HostAddresses struct for the local machines interface IP addresses.
func LocalHostAddresses() (ha HostAddresses, err error) {
ifs, err := net.Interfaces()
if err != nil {
return
}
for _, iface := range ifs {
if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
// Interface is either loopback of not up
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
var a HostAddress
if ip.To16() == nil {
//neither IPv4 or IPv6
continue
}
if ip.To4() != nil {
//Is IPv4
a.AddrType = addrtype.IPv4
a.Address = ip.To4()
} else {
a.AddrType = addrtype.IPv6
a.Address = ip.To16()
}
ha = append(ha, a)
}
}
return ha, nil
}
// HostAddressesFromNetIPs returns a HostAddresses type from a slice of net.IP
func HostAddressesFromNetIPs(ips []net.IP) (ha HostAddresses) {
for _, ip := range ips {
ha = append(ha, HostAddressFromNetIP(ip))
}
return ha
}
// HostAddressFromNetIP returns a HostAddress type from a net.IP
func HostAddressFromNetIP(ip net.IP) HostAddress {
if ip.To4() != nil {
//Is IPv4
return HostAddress{
AddrType: addrtype.IPv4,
Address: ip.To4(),
}
}
return HostAddress{
AddrType: addrtype.IPv6,
Address: ip.To16(),
}
}
// HostAddressesEqual tests if two HostAddress slices are equal.
func HostAddressesEqual(h, a []HostAddress) bool {
if len(h) != len(a) {
return false
}
for _, e := range a {
var found bool
for _, i := range h {
if e.Equal(i) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
// HostAddressesContains tests if a HostAddress is contained in a HostAddress slice.
func HostAddressesContains(h []HostAddress, a HostAddress) bool {
for _, e := range h {
if e.Equal(a) {
return true
}
}
return false
}
// Equal tests if the HostAddress is equal to another HostAddress provided.
func (h *HostAddress) Equal(a HostAddress) bool {
if h.AddrType != a.AddrType {
return false
}
return bytes.Equal(h.Address, a.Address)
}
// Contains tests if a HostAddress is contained within the HostAddresses struct.
func (h *HostAddresses) Contains(a HostAddress) bool {
for _, e := range *h {
if e.Equal(a) {
return true
}
}
return false
}
// Equal tests if a HostAddress slice is equal to the HostAddresses struct.
func (h *HostAddresses) Equal(a []HostAddress) bool {
if len(*h) != len(a) {
return false
}
for _, e := range a {
if !h.Contains(e) {
return false
}
}
return true
}