github.com/vmware/govmomi@v0.51.0/toolbox/guest_info.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package toolbox 6 7 import ( 8 "bytes" 9 "fmt" 10 "net" 11 12 xdr "github.com/rasky/go-xdr/xdr2" 13 ) 14 15 // Defs from: open-vm-tools/lib/guestRpc/nicinfo.x 16 17 type TypedIPAddress struct { 18 Type int32 19 Address []byte 20 } 21 22 type IPAddressEntry struct { 23 Address TypedIPAddress 24 PrefixLength uint32 25 Origin *int32 `xdr:"optional"` 26 Status *int32 `xdr:"optional"` 27 } 28 29 type InetCidrRouteEntry struct { 30 Dest TypedIPAddress 31 PrefixLength uint32 32 NextHop *TypedIPAddress `xdr:"optional"` 33 IfIndex uint32 34 Type int32 35 Metric uint32 36 } 37 38 type DNSConfigInfo struct { 39 HostName *string `xdr:"optional"` 40 DomainName *string `xdr:"optional"` 41 Servers []TypedIPAddress 42 Search *string `xdr:"optional"` 43 } 44 45 type WinsConfigInfo struct { 46 Primary TypedIPAddress 47 Secondary TypedIPAddress 48 } 49 50 type DhcpConfigInfo struct { 51 Enabled bool 52 Settings string 53 } 54 55 type GuestNicV3 struct { 56 MacAddress string 57 IPs []IPAddressEntry 58 DNSConfigInfo *DNSConfigInfo `xdr:"optional"` 59 WinsConfigInfo *WinsConfigInfo `xdr:"optional"` 60 DhcpConfigInfov4 *DhcpConfigInfo `xdr:"optional"` 61 DhcpConfigInfov6 *DhcpConfigInfo `xdr:"optional"` 62 } 63 64 type NicInfoV3 struct { 65 Nics []GuestNicV3 66 Routes []InetCidrRouteEntry 67 DNSConfigInfo *DNSConfigInfo `xdr:"optional"` 68 WinsConfigInfo *WinsConfigInfo `xdr:"optional"` 69 DhcpConfigInfov4 *DhcpConfigInfo `xdr:"optional"` 70 DhcpConfigInfov6 *DhcpConfigInfo `xdr:"optional"` 71 } 72 73 type GuestNicInfo struct { 74 Version int32 75 V3 *NicInfoV3 `xdr:"optional"` 76 } 77 78 func EncodeXDR(val any) ([]byte, error) { 79 var buf bytes.Buffer 80 81 _, err := xdr.Marshal(&buf, val) 82 if err != nil { 83 return nil, err 84 } 85 86 return buf.Bytes(), nil 87 } 88 89 func DecodeXDR(buf []byte, val any) error { 90 r := bytes.NewReader(buf) 91 _, err := xdr.Unmarshal(r, val) 92 return err 93 } 94 95 func NewGuestNicInfo() *GuestNicInfo { 96 return &GuestNicInfo{ 97 Version: 3, 98 V3: &NicInfoV3{}, 99 } 100 } 101 102 func (nic *GuestNicV3) AddIP(addr net.Addr) { 103 ip, ok := addr.(*net.IPNet) 104 if !ok { 105 return 106 } 107 108 kind := int32(1) // IAT_IPV4 109 if ip.IP.To4() == nil { 110 kind = 2 // IAT_IPV6 111 } else { 112 ip.IP = ip.IP.To4() // convert to 4-byte representation 113 } 114 115 size, _ := ip.Mask.Size() 116 117 // nicinfo.x defines enum IpAddressStatus, but vmtoolsd only uses IAS_PREFERRED 118 var status int32 = 1 // IAS_PREFERRED 119 120 e := IPAddressEntry{ 121 Address: TypedIPAddress{ 122 Type: kind, 123 Address: []byte(ip.IP), 124 }, 125 PrefixLength: uint32(size), 126 Status: &status, 127 } 128 129 nic.IPs = append(nic.IPs, e) 130 } 131 132 func GuestInfoCommand(kind int, req []byte) []byte { 133 request := fmt.Sprintf("SetGuestInfo %d ", kind) 134 return append([]byte(request), req...) 135 } 136 137 var ( 138 netInterfaces = net.Interfaces 139 maxNics = 16 // guestRpc/nicinfo.x:NICINFO_MAX_NICS 140 ) 141 142 func DefaultGuestNicInfo() *GuestNicInfo { 143 proto := NewGuestNicInfo() 144 info := proto.V3 145 // #nosec: Errors unhandled 146 ifs, _ := netInterfaces() 147 148 for _, i := range ifs { 149 if i.Flags&net.FlagLoopback == net.FlagLoopback { 150 continue 151 } 152 153 if len(i.HardwareAddr) == 0 { 154 continue // Not useful from outside the guest without a MAC 155 } 156 157 // #nosec: Errors unhandled 158 addrs, _ := i.Addrs() 159 160 if len(addrs) == 0 { 161 continue // Not useful from outside the guest without an IP 162 } 163 164 nic := GuestNicV3{ 165 MacAddress: i.HardwareAddr.String(), 166 } 167 168 for _, addr := range addrs { 169 nic.AddIP(addr) 170 } 171 172 info.Nics = append(info.Nics, nic) 173 174 if len(info.Nics) >= maxNics { 175 break 176 } 177 } 178 179 return proto 180 } 181 182 func GuestInfoNicInfoRequest() ([]byte, error) { 183 r, err := EncodeXDR(DefaultGuestNicInfo()) 184 if err != nil { 185 return nil, err 186 } 187 188 return GuestInfoCommand(9 /*INFO_IPADDRESS_V3*/, r), nil 189 }