package govmtools import ( "fmt" "github.com/ptrcnull/vsock" "golang.org/x/sys/unix" ) type PacketType uint32 const ( PacketTypeData PacketType = iota + 1 PacketTypePing ) type FieldID uint32 const ( FieldIDType FieldID = iota + 1 FieldIDPayload FieldIDFastClose ) type FieldType uint32 const ( FieldEmpty FieldType = iota FieldInt64 FieldString FieldInt64List FieldStringList FieldMax ) type GuestInfoType uint32 const ( GuestInfoError GuestInfoType = iota GuestInfoDnsName GuestInfoIpAddress GuestInfoDiskFreeSpace GuestInfoBuildNumber GuestInfoOsNameFull GuestInfoOsName GuestInfoUptime GuestInfoMemory GuestInfoIpAddressV2 GuestInfoIpAddressV3 GuestInfoOsDetailed GuestInfoMax ) const GuestConnectPort = 976 const ContextID = unix.VMADDR_CID_HYPERVISOR type Socket struct { conn *vsock.Conn } func NewSocket() (*Socket, error) { conn, err := vsock.Dial(ContextID, GuestConnectPort) if err != nil { return nil, fmt.Errorf("connect: %w", err) } return &Socket{ conn: conn, }, nil } func (s *Socket) SendCommand(cmd string) error { err := s.WritePacket([]Field{ { Type: FieldInt64, ID: FieldIDType, Value: PacketTypeData, }, { Type: FieldEmpty, }, { Type: FieldString, ID: FieldIDPayload, Value: cmd, }, }) if err != nil { return fmt.Errorf("write packet: %w", err) } res, err := s.ReadPacket() if err != nil { return fmt.Errorf("read packet: %w", err) } if len(res) != 1 { return fmt.Errorf("unexpected response length: %d", len(res)) } field := res[0] if field.Type != FieldString { return fmt.Errorf("unexpected response type: %d", field.Type) } if field.ID != FieldIDPayload { return fmt.Errorf("unexpected response id: %d", field.ID) } response := field.Value.(string) if response != "1 " { return fmt.Errorf("unexpected response: %s", response) } return nil } func (s *Socket) SetGuestInfo(messageType GuestInfoType, message string) { s.MustSendCommand(fmt.Sprintf("SetGuestInfo %d %s", messageType, message)) } func (s *Socket) MustSendCommand(cmd string) { err := s.SendCommand(cmd) if err != nil { panic(err) } } func (s *Socket) ReportVersionData() error { data := []string{ "description " + Name + " " + Version + " build " + BuildNumber, "versionString " + Version, "versionNumber " + VersionNumber, "buildNumber " + BuildNumber, } for _, value := range data { err := s.SendCommand("info-set guestinfo.vmtools." + value + "\x00") if err != nil { return fmt.Errorf("send: %w", err) } } return nil }