github.com/binkynet/BinkyNet@v1.12.1-0.20240421190447-da4e34c20be0/apis/v1/serviceinfo.go (about) 1 // Copyright 2020 Ewout Prangsma 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Author Ewout Prangsma 16 // 17 18 package v1 19 20 import ( 21 context "context" 22 "crypto/sha1" 23 fmt "fmt" 24 "io/ioutil" 25 "net" 26 "os" 27 "runtime" 28 "sort" 29 "strconv" 30 "strings" 31 32 "github.com/grandcat/zeroconf" 33 ) 34 35 const ( 36 textVersion = "version" 37 textAPIVersion = "api_version" 38 textSecure = "secure" 39 ) 40 41 // ParseServiceInfo parses a ServiceEntry into a ServiceInfo message. 42 func ParseServiceInfo(se *zeroconf.ServiceEntry) (*ServiceInfo, error) { 43 result := &ServiceInfo{ 44 ApiPort: int32(se.Port), 45 ApiAddress: se.HostName, 46 Secure: true, 47 } 48 if len(se.AddrIPv4) > 0 { 49 result.ApiAddress = se.AddrIPv4[0].String() 50 } else if len(se.AddrIPv6) > 0 { 51 result.ApiAddress = se.AddrIPv6[0].String() 52 } 53 for _, t := range se.Text { 54 parts := strings.SplitN(t, "=", 2) 55 if len(parts) != 2 { 56 continue 57 } 58 switch parts[0] { 59 case textVersion: 60 result.Version = parts[1] 61 case textAPIVersion: 62 result.ApiVersion = parts[1] 63 case textSecure: 64 if b, err := strconv.ParseBool(parts[1]); err == nil { 65 result.Secure = b 66 } 67 } 68 } 69 return result, nil 70 } 71 72 // RegisterServiceEntry runs a registration service for the given service entry 73 // until the given context is canceled. 74 func RegisterServiceEntry(ctx context.Context, serviceType string, info ServiceInfo) error { 75 text := []string{ 76 textVersion + "=" + info.GetVersion(), 77 textAPIVersion + "=" + info.GetApiVersion(), 78 textSecure + "=" + strconv.FormatBool(info.GetSecure()), 79 } 80 instance, err := os.Hostname() 81 if err != nil { 82 instance, err = CreateHostID() 83 if err != nil { 84 return err 85 } 86 } 87 88 var ifaces []net.Interface 89 if host, found := GetServiceInfoHost(ctx); found && host != "" { 90 // Find interfaces with given IP 91 var selectedIFaces []net.Interface 92 allInterfaces, err := net.Interfaces() 93 if err != nil { 94 return err 95 } 96 for _, ifi := range allInterfaces { 97 if (ifi.Flags & net.FlagUp) == 0 { 98 continue 99 } 100 if (ifi.Flags & net.FlagMulticast) == 0 { 101 continue 102 } 103 addrs, _ := ifi.Addrs() 104 for _, addr := range addrs { 105 addrStr := addr.String() 106 if addrStr == host || strings.HasPrefix(addrStr, host+"/") { 107 selectedIFaces = append(selectedIFaces, ifi) 108 break 109 } 110 } 111 } 112 if len(selectedIFaces) == 0 && host != "0.0.0.0" { 113 return fmt.Errorf("Did not find interface with address '%s'", host) 114 } 115 ifaces = selectedIFaces 116 } 117 118 srv, err := zeroconf.Register(instance, serviceType, "local.", int(info.GetApiPort()), text, ifaces) 119 if err != nil { 120 return err 121 } 122 <-ctx.Done() 123 srv.Shutdown() 124 return nil 125 } 126 127 // CreateHostID creates a host ID based on network hardware addresses. 128 func CreateHostID() (string, error) { 129 if content, err := ioutil.ReadFile("/etc/machine-id"); err == nil { 130 content = []byte(strings.TrimSpace(string(content))) 131 id := fmt.Sprintf("%x", sha1.Sum(content)) 132 return id[:10], nil 133 } 134 135 ifs, err := net.Interfaces() 136 if err != nil { 137 return "", err 138 } 139 list := make([]string, 0, len(ifs)) 140 for _, v := range ifs { 141 f := v.Flags 142 if f&net.FlagUp != 0 && f&net.FlagLoopback == 0 { 143 fmt.Printf("Using intf %s with addr %s\n", v.Name, v.HardwareAddr.String()) 144 h := v.HardwareAddr.String() 145 if len(h) > 0 { 146 list = append(list, h) 147 } 148 } 149 } 150 sort.Strings(list) // sort host IDs 151 list = append(list, runtime.GOOS, runtime.GOARCH) 152 data := []byte(strings.Join(list, ",")) 153 id := fmt.Sprintf("%x", sha1.Sum(data)) 154 return id[:10], nil 155 }