github.com/vmware/govmomi@v0.37.1/toolbox/guest_info.go (about)

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