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  }