From 165092c79acf2030421f21358606ff98daac8c79 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sat, 21 May 2022 11:52:35 -0500 Subject: [PATCH] Network utilities --- go.mod | 1 - go.sum | 2 - logging/journal/backend.go | 2 +- util/network.go | 99 ++++++++++++++++++++++++++++++++++++++ util/string.go | 51 +++++++++++++++++--- 5 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 util/network.go diff --git a/go.mod b/go.mod index bd7bef4..72b861b 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,6 @@ require ( k8s.io/apiextensions-apiserver v0.24.0 k8s.io/apimachinery v0.24.0 k8s.io/client-go v0.24.0 - k8s.io/klog v1.0.0 k8s.io/klog/v2 v2.60.1 ) diff --git a/go.sum b/go.sum index 88ec0c4..f5bdb41 100644 --- a/go.sum +++ b/go.sum @@ -1616,8 +1616,6 @@ k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= diff --git a/logging/journal/backend.go b/logging/journal/backend.go index 56b8a0c..6ddc1fb 100644 --- a/logging/journal/backend.go +++ b/logging/journal/backend.go @@ -71,7 +71,7 @@ func (self *Backend) NewMessage(name []string, level logging.Level, depth int) l var prefix string if name := strings.Join(name, "."); len(name) > 0 { - prefix = name + ": " + prefix = "[" + name + "] " } return NewMessage(priority, prefix) diff --git a/util/network.go b/util/network.go new file mode 100644 index 0000000..b942f12 --- /dev/null +++ b/util/network.go @@ -0,0 +1,99 @@ +package util + +import ( + "fmt" + "net" + "net/netip" + "strings" +) + +func JoinIPAddressPort(address string, port int) string { + if IsIPv6(address) { + return fmt.Sprintf("[%s]:%d", address, port) + } else { + return fmt.Sprintf("%s:%d", address, port) + } +} + +func IsIPv6(address string) bool { + // See: https://stackoverflow.com/questions/22751035/golang-distinguish-ipv4-ipv6 + return strings.Contains(address, ":") +} + +func IsUDPAddrEqual(a *net.UDPAddr, b *net.UDPAddr) bool { + return a.IP.Equal(b.IP) && (a.Port == b.Port) && (a.Zone == b.Zone) +} + +func ToReachableIPAddress(address string) (string, error) { + if net.ParseIP(address).IsUnspecified() { + v6 := IsIPv6(address) + if interfaces, err := net.Interfaces(); err == nil { + for _, interface_ := range interfaces { + if (interface_.Flags&net.FlagLoopback == 0) && (interface_.Flags&net.FlagUp != 0) { + if addrs, err := interface_.Addrs(); err == nil { + for _, addr := range addrs { + if addr_, ok := addr.(*net.IPNet); ok { + //DumpIPAddress(addr_.IP.String()) + if addr_.IP.IsGlobalUnicast() { + ip := addr_.IP.String() + if v6 == IsIPv6(ip) { + return ip, nil + } + } + } + } + } else { + return "", err + } + } + } + return "", fmt.Errorf("cannot find an equivalent reachable address for: %s", address) + } else { + return "", err + } + } + + return address, nil +} + +func ToBroadcastIPAddress(address string) (string, error) { + // Note: net.ParseIP can't parse IPv6 zone + if ip, err := netip.ParseAddr(address); err == nil { + if !ip.IsMulticast() { + return "", fmt.Errorf("not a multicast address: %s", address) + } + + if IsIPv6(address) && ip.Zone() == "" { + if interfaces, err := net.Interfaces(); err == nil { + for _, interface_ := range interfaces { + //fmt.Printf("%s\n", interface_.Flags.String()) + if (interface_.Flags&net.FlagLoopback == 0) && (interface_.Flags&net.FlagUp != 0) && + (interface_.Flags&net.FlagBroadcast != 0) && (interface_.Flags&net.FlagMulticast != 0) { + return address + "%" + interface_.Name, nil + } + } + } else { + return "", err + } + return "", fmt.Errorf("cannot find a zone for: %s", address) + } + + return address, nil + } else { + return "", err + } +} + +func DumpIPAddress(address any) { + // Note: net.ParseIP can't parse IPv6 zone + ip := netip.MustParseAddr(ToString(address)) + fmt.Printf("address: %s\n", ip) + fmt.Printf(" global unicast: %t\n", ip.IsGlobalUnicast()) + fmt.Printf(" interface local multicast: %t\n", ip.IsInterfaceLocalMulticast()) + fmt.Printf(" link local multicast: %t\n", ip.IsLinkLocalMulticast()) + fmt.Printf(" link local unicast: %t\n", ip.IsLinkLocalUnicast()) + fmt.Printf(" loopback: %t\n", ip.IsLoopback()) + fmt.Printf(" multicast: %t\n", ip.IsMulticast()) + fmt.Printf(" private: %t\n", ip.IsPrivate()) + fmt.Printf(" unspecified: %t\n", ip.IsUnspecified()) +} diff --git a/util/string.go b/util/string.go index e09c723..cd12789 100644 --- a/util/string.go +++ b/util/string.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" "strconv" - "strings" + stringspkg "strings" "unsafe" ) @@ -45,13 +45,48 @@ func ToString(value any) string { } } -func Joinq(s []string, sep string) string { - var builder strings.Builder - last := len(s) - 1 - for i, s_ := range s { - builder.WriteString(strconv.Quote(s_)) - if i != last { - builder.WriteString(sep) +func ToStrings(values []any) []string { + length := len(values) + if length == 0 { + return nil + } + strings := make([]string, length) + for index, value := range values { + strings[index] = ToString(value) + } + return strings +} + +func JoinQuote(strings []string, separator string) string { + var builder stringspkg.Builder + ultimateIndex := len(strings) - 1 + for index, value := range strings { + builder.WriteString(strconv.Quote(value)) + if index != ultimateIndex { + builder.WriteString(separator) + } + } + return builder.String() +} + +func JoinQuoteL(strings []string, separator string, lastSeparator string, coupleSeparator string) string { + var builder stringspkg.Builder + if len(strings) == 2 { + builder.WriteString(strconv.Quote(strings[0])) + builder.WriteString(coupleSeparator) + builder.WriteString(strconv.Quote(strings[1])) + } else { + ultimateIndex := len(strings) - 1 + penultimateIndex := ultimateIndex - 1 + for index, value := range strings { + builder.WriteString(strconv.Quote(value)) + if index != ultimateIndex { + if index == penultimateIndex { + builder.WriteString(lastSeparator) + } else { + builder.WriteString(separator) + } + } } } return builder.String()