Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Issue vmware#742
Issue vmware#407
Issue vmware#406
  • Loading branch information
dougm committed Jun 28, 2016
1 parent 6c27b80 commit f774f21
Show file tree
Hide file tree
Showing 11 changed files with 961 additions and 0 deletions.
39 changes: 39 additions & 0 deletions cmd/toolbox/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"log"

"github.com/vmware/vic/pkg/vsphere/toolbox"
)

func main() {
in := toolbox.NewBackdoorChannelIn()
out := toolbox.NewBackdoorChannelOut()

service := toolbox.NewService(in, out)

toolbox.RegisterVixRelayedCommandHandler(service)

err := service.Start()
if err != nil {
log.Fatal(err)
}

defer service.Stop()

service.Run()
}
69 changes: 69 additions & 0 deletions pkg/vsphere/toolbox/backdoor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toolbox

import (
"errors"

"github.com/vmware/vmw-guestinfo/message"
"github.com/vmware/vmw-guestinfo/vmcheck"
)

const (
rpciProtocol uint32 = 0x49435052
tcloProtocol uint32 = 0x4f4c4354
)

var (
ErrNotVirtualWorld = errors.New("not in a virtual world")
)

type backdoorChannel struct {
protocol uint32

*message.Channel
}

func (b *backdoorChannel) Start() error {
if !vmcheck.IsVirtualWorld() {
return ErrNotVirtualWorld
}

channel, err := message.NewChannel(b.protocol)
if err != nil {
return err
}

b.Channel = channel

return nil
}

func (b *backdoorChannel) Stop() error {
err := b.Channel.Close()
return err
}

func NewBackdoorChannelOut() Channel {
return &backdoorChannel{
protocol: rpciProtocol,
}
}

func NewBackdoorChannelIn() Channel {
return &backdoorChannel{
protocol: tcloProtocol,
}
}
17 changes: 17 additions & 0 deletions pkg/vsphere/toolbox/backdoor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toolbox

var _ Channel = new(backdoorChannel)
22 changes: 22 additions & 0 deletions pkg/vsphere/toolbox/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toolbox

type Channel interface {
Start() error
Stop() error
Send([]byte) error
Receive() ([]byte, error)
}
74 changes: 74 additions & 0 deletions pkg/vsphere/toolbox/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toolbox

import (
"encoding/hex"
"fmt"
"io"
"os"
)

var (
Debug = true // TODO: make optional
)

type DebugChannel struct {
c Channel
log io.Writer
}

func NewDebugChannel(c Channel) Channel {
if !Debug {
return c
}

return &DebugChannel{
c: c,
log: os.Stderr,
}
}

func (d *DebugChannel) Start() error {
err := d.c.Start()

return err
}

func (d *DebugChannel) Stop() error {
err := d.c.Stop()

return err
}

func (d *DebugChannel) Send(buf []byte) error {
if len(buf) > 0 {
fmt.Fprintf(d.log, "SEND %d...\n%s\n", len(buf), hex.Dump(buf))
}

err := d.c.Send(buf)

return err
}

func (d *DebugChannel) Receive() ([]byte, error) {
buf, err := d.c.Receive()

if err == nil {
fmt.Fprintf(d.log, "RECV %d...\n%s\n", len(buf), hex.Dump(buf))
}

return buf, err
}
163 changes: 163 additions & 0 deletions pkg/vsphere/toolbox/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright 2016 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package toolbox

import (
"bytes"
"fmt"
"log"
"net"
"os"
"time"
)

type Handler func([]byte) ([]byte, error)

type Service struct {
name string
in Channel
out Channel
handlers map[string]Handler

PrimaryIP func() string
}

func NewService(rpcIn Channel, rpcOut Channel) *Service {
return &Service{
name: "toolbox", // Same name used by vmtoolsd
in: NewDebugChannel(rpcIn),
out: NewDebugChannel(rpcOut),
handlers: make(map[string]Handler),
PrimaryIP: DefaultIP,
}
}

func (s *Service) RegisterHandler(name string, handler Handler) {
s.handlers[name] = handler
}

func (s *Service) Start() error {
s.RegisterHandler("reset", s.Reset)
s.RegisterHandler("ping", s.Ping)
s.RegisterHandler("Set_Option", s.SetOption)

err := s.in.Start()
if err != nil {
return err
}

err = s.out.Start()
if err != nil {
return err
}

return nil
}

func (s *Service) Stop() {
_ = s.in.Stop()
_ = s.out.Stop()
}

func (s *Service) Run() {
for {
_ = s.in.Send(nil) // POKE

request, _ := s.in.Receive()

if len(request) > 0 {
response := s.Dispatch(request)

_ = s.in.Send(response)
}

<-time.After(time.Second)
}
}

func (s *Service) Dispatch(request []byte) []byte {
msg := bytes.SplitN(request, []byte{' '}, 2)
name := msg[0]

// Trim NULL byte terminator
if len(name) > 0 && name[len(name)-1] == 0 {
name = name[:len(name)-1]
}

handler, ok := s.handlers[string(name)]

if !ok {
log.Printf("unknown command: '%s'\n", name)
return []byte("Unknown Command")
}

var args []byte
if len(msg) == 2 {
args = msg[1]
}

response, err := handler(args)
if err == nil {
response = append([]byte("OK "), response...)
} else {
log.Printf("error calling %s: %s\n", name, err)
response = append([]byte("ERR "), response...)
}

return response
}

func (s *Service) Reset([]byte) ([]byte, error) {
return []byte("ATR " + s.name), nil
}

func (s *Service) Ping([]byte) ([]byte, error) {
return nil, nil
}

func DefaultIP() string {
addrs, err := net.InterfaceAddrs()
if err == nil {
for _, addr := range addrs {
if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() {
if ip.IP.To4() != nil {
return ip.IP.String()
}
}
}
}

return ""
}

func (s *Service) SetOption(args []byte) ([]byte, error) {
opts := bytes.SplitN(args, []byte{' '}, 2)
if Debug {
fmt.Fprintf(os.Stderr, "set option %s=%s\n", string(opts[0]), string(opts[1]))
}

switch string(opts[0]) {
case "broadcastIP": // TODO: const-ify
if opts[1][0] == 1 {
ip := DefaultIP()
msg := fmt.Sprintf("info-set guestinfo.ip %s", ip)
return nil, s.out.Send([]byte(msg))
}
default:
// TODO: handle other options...
}

return nil, nil
}
Loading

0 comments on commit f774f21

Please sign in to comment.