Compare commits

..

No commits in common. "master" and "1.0" have entirely different histories.
master ... 1.0

47 changed files with 174 additions and 578 deletions

View File

@ -1,129 +0,0 @@
version: 2 # use CircleCI 2.0
jobs: # basic units of work in a run
build: # runs not using Workflows must have a `build` job as entry point
docker: # run the steps with Docker
# CircleCI Go images available at: https://hub.docker.com/r/circleci/golang/
- image: circleci/golang:1.12
# CircleCI PostgreSQL images available at: https://hub.docker.com/r/circleci/postgres/
- image: circleci/postgres:9.6-alpine
environment: # environment variables for primary container
POSTGRES_USER: circleci-demo-go
POSTGRES_DB: circle_test
parallelism: 2
environment: # environment variables for the build itself
TEST_RESULTS: /tmp/test-results # path to where test results will be saved
steps: # steps that comprise the `build` job
- checkout # check out source code to working directory
- run: mkdir -p $TEST_RESULTS # create the test results directory
- restore_cache: # restores saved cache if no changes are detected since last run
keys:
- go-mod-v4-{{ checksum "go.sum" }}
# Wait for Postgres to be ready before proceeding
- run:
name: Waiting for Postgres to be ready
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Run unit tests
environment: # environment variables for the database url and path to migration files
CONTACTS_DB_URL: "postgres://circleci-demo-go@localhost:5432/circle_test?sslmode=disable"
CONTACTS_DB_MIGRATIONS: /home/circleci/project/db/migrations
# store the results of our tests in the $TEST_RESULTS directory
command: |
PACKAGE_NAMES=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname)
gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES
# Build
- run:
name: Build and package all OS flavors
command: |
#!/bin/bash
sum="sha1sum"
# VERSION=`date -u +%Y%m%d`
VERSION="v1.11"
LDFLAGS="-X main.VERSION=$VERSION -s -w"
GCFLAGS=""
if ! hash sha1sum 2>/dev/null; then
if ! hash shasum 2>/dev/null; then
echo "I can't see 'sha1sum' or 'shasum'"
echo "Please install one of them!"
exit
fi
sum="shasum"
fi
UPX=false
if hash upx 2>/dev/null; then
UPX=true
fi
OSES=( linux darwin windows )
ARCHS=(amd64 386 )
for os in ${OSES[@]}; do
for arch in ${ARCHS[@]}; do
suffix=""
if [ "$os" == "windows" ]
then
suffix=".exe"
fi
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o ./dist/${os}_${arch}/recorder${suffix} ./recorder/cmd
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o ./dist/${os}_${arch}/player${suffix} ./player/cmd
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o ./dist/${os}_${arch}/proxy${suffix} ./proxy/cmd
if $UPX; then upx -9 client_${os}_${arch}${suffix} server_${os}_${arch}${suffix};fi
# tar -zcf ./dist/${CIRCLE_PROJECT_REPONAME}-${os}-${arch}-$VERSION.tar.gz ./dist/${os}_${arch}/proxy${suffix} ./dist/${os}_${arch}/player${suffix} ./dist/${os}_${arch}/recorder${suffix}
cd dist/${os}_${arch}/
zip -D -q -r ../${CIRCLE_PROJECT_REPONAME}-${os}-${arch}-$VERSION.zip proxy${suffix} player${suffix} recorder${suffix}
cd ../..
export
$sum ./dist/${CIRCLE_PROJECT_REPONAME}-${os}-${arch}-$VERSION.zip
rm -rf ./dist/${os}_${arch}/
done
done
- store_artifacts: # upload test summary for display in Artifacts
path: ./dist
destination: release-artifacts
# - run: make # pull and build dependencies for the project
# - save_cache:
# key: go-mod-v4-{{ checksum "go.sum" }}
# paths:
# - "/go/pkg/mod"
# - run:
# name: Start service
# environment:
# CONTACTS_DB_URL: "postgres://circleci-demo-go@localhost:5432/circle_test?sslmode=disable"
# CONTACTS_DB_MIGRATIONS: /home/circleci/project/db/migrations
# command: ./workdir/contacts
# background: true # keep service running and proceed to next step
# - run:
# name: Validate service is working
# command: |
# sleep 5
# curl --retry 10 --retry-delay 1 -X POST --header "Content-Type: application/json" -d '{"email":"test@example.com","name":"Test User"}' http://localhost:8080/contacts
# - store_artifacts: # upload test summary for display in Artifacts
# path: /tmp/test-results
# destination: raw-test-output
# - store_test_results: # upload test results for display in Test Summary
# path: /tmp/test-results
workflows:
version: 2
build-workflow:
jobs:
- build

5
.gitignore vendored
View File

@ -2,8 +2,3 @@
*.debug *.debug
*.test *.test
debug debug
/dist
vncproxy
prox
cmd
aa

View File

@ -1,37 +1,30 @@
# VncProxy [![CircleCI](https://circleci.com/gh/amitbet/vncproxy/tree/master.svg?style=shield)](https://circleci.com/gh/amitbet/vncproxy/tree/master) [![MIT Licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/CircleCI-Public/circleci-demo-go/master/LICENSE.md) # VncProxy
An RFB proxy, written in go that can save and replay FBS files An RFB proxy, written in go that can save and replay FBS files
* Supports all modern encodings & most useful pseudo-encodings * supports all modern encodings & most useful pseudo-encodings
* Supports multiple VNC client connections & multi servers (chosen by sessionId) * supports multiple VNC client connections & multi servers (chosen by sessionId)
* Supports being a "websockify" proxy (for web clients like NoVnc) * supports being a "websockify" proxy (for web clients like NoVnc)
* Produces FBS files compatible with [tightvnc's rfb player](https://www.tightvnc.com/rfbplayer.php) (while using tight's default 3Byte color format) * produces FBS files compatible with tightvnc player (while using tight's default 3Byte color format)
* Can also be used as: * can also be used as:
* A screen recorder vnc-client * a screen recorder vnc-client
* A replay server to show fbs recordings to connecting clients * a replay server to show fbs recordings to connecting clients
- Tested on tight encoding with: **This is still a work in progress, and requires some error handling and general tidying up,
but the code is already working (see main, proxy_test & player_test)**
- tested on tight encoding with:
- Tightvnc (client + java client + server) - Tightvnc (client + java client + server)
- FBS player (tightVnc Java player) - FBS player (tightVnc Java player)
- NoVnc(web client) => use -wsPort to open a websocket - NoVnc(web client)
- ChickenOfTheVnc(client) - ChickenOfTheVnc(client)
- VineVnc(server) - VineVnc(server)
- TigerVnc(client) - TigerVnc(client)
- Qemu vnc(server)
## Usage
**Some very usable cmdline executables are Coming Soon...**
### Executables (see releases) Code samples can be found by looking at:
* proxy - the actual recording proxy, supports listening to tcp & ws ports and recording traffic to fbs files * main.go (fbs recording vnc client)
* recorder - connects to a vnc server as a client and records the screen * Connects, records to FBS file
* player - a toy player that will replay a given fbs file to all incoming connections * Programmed to quit after 10 seconds
## Usage:
recorder -recFile=./recording.rbs -targHost=192.168.0.100 -targPort=5903 -targPass=@@@@@
player -fbsFile=./myrec.fbs -tcpPort=5905
proxy -recDir=./recordings/ -targHost=192.168.0.100 -targPort=5903 -targPass=@@@@@ -tcpPort=5903 -wsPort=5905 -vncPass=@!@!@!
### Code usage examples
* player/main.go (fbs recording vnc client)
   * Connects as client, records to FBS file
* proxy/proxy_test.go (vnc proxy with recording) * proxy/proxy_test.go (vnc proxy with recording)
* Listens to both Tcp and WS ports * Listens to both Tcp and WS ports
* Proxies connections to a hard-coded localhost vnc server * Proxies connections to a hard-coded localhost vnc server
@ -63,4 +56,4 @@ The Recorder uses channels and runs in parallel to avoid hampering the communica
![Image of Arch](https://github.com/amitbet/vncproxy/blob/master/architecture/player-arch.png?raw=true) ![Image of Arch](https://github.com/amitbet/vncproxy/blob/master/architecture/player-arch.png?raw=true)
The code is based on several implementations of go-vnc including the original one by *Mitchell Hashimoto*, and the recentely active fork by *Vasiliy Tolstov*. The code is based on several implementations of go-vnc including the original one by *Mitchell Hashimoto*, and the recentely active fork which belongs to *Vasiliy Tolstov*.

View File

@ -1,48 +1,4 @@
#!/bin/bash export GOOS="darwin"
sum="sha1sum" go build -o ./dist/recorder ./recorder/cmd
go build -o ./dist/player ./player/cmd
# VERSION=`date -u +%Y%m%d` go build -o ./dist/proxy ./proxy/cmd
VERSION="v1.11"
LDFLAGS="-X main.VERSION=$VERSION -s -w"
GCFLAGS=""
if ! hash sha1sum 2>/dev/null; then
if ! hash shasum 2>/dev/null; then
echo "I can't see 'sha1sum' or 'shasum'"
echo "Please install one of them!"
exit
fi
sum="shasum"
fi
UPX=false
if hash upx 2>/dev/null; then
UPX=true
fi
OSES=( linux darwin windows )
ARCHS=(amd64 386 )
for os in ${OSES[@]}; do
for arch in ${ARCHS[@]}; do
suffix=""
if [ "$os" == "windows" ]
then
suffix=".exe"
fi
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o ./dist/${os}_${arch}/recorder${suffix} ./recorder/cmd
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o ./dist/${os}_${arch}/player${suffix} ./player/cmd
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o ./dist/${os}_${arch}/proxy${suffix} ./proxy/cmd
if $UPX; then upx -9 client_${os}_${arch}${suffix} server_${os}_${arch}${suffix};fi
# tar -zcf ./dist/vncproxy-${os}-${arch}-$VERSION.tar.gz ./dist/${os}_${arch}/proxy${suffix} ./dist/${os}_${arch}/player${suffix} ./dist/${os}_${arch}/recorder${suffix}
cd dist/${os}_${arch}/
zip -D -q -r ../vncproxy-${os}-${arch}-$VERSION.zip proxy${suffix} player${suffix} recorder${suffix}
cd ../..
$sum ./dist/vncproxy-${os}-${arch}-$VERSION.zip
done
done

View File

@ -4,11 +4,11 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/amitbet/vncproxy/common"
"github.com/amitbet/vncproxy/logger"
"io" "io"
"net" "net"
"unicode" "unicode"
"vncproxy/common"
"vncproxy/logger"
) )
// A ServerMessage implements a message sent from the server to the client. // A ServerMessage implements a message sent from the server to the client.
@ -116,9 +116,9 @@ func (c *ClientConn) Read(bytes []byte) (n int, err error) {
return c.conn.Read(bytes) return c.conn.Read(bytes)
} }
// func (c *ClientConn) CurrentColorMap() *common.ColorMap { func (c *ClientConn) CurrentColorMap() *common.ColorMap {
// return &c.ColorMap return &c.ColorMap
// } }
// CutText tells the server that the client has new text in its cut buffer. // CutText tells the server that the client has new text in its cut buffer.
// The text string MUST only contain Latin-1 characters. This encoding // The text string MUST only contain Latin-1 characters. This encoding
@ -146,7 +146,7 @@ func (c *ClientConn) CutText(text string) error {
for _, char := range text { for _, char := range text {
if char > unicode.MaxLatin1 { if char > unicode.MaxLatin1 {
return fmt.Errorf("Character '%v' is not valid Latin-1", char) return fmt.Errorf("Character '%s' is not valid Latin-1", char)
} }
if err := binary.Write(&buf, binary.BigEndian, uint8(char)); err != nil { if err := binary.Write(&buf, binary.BigEndian, uint8(char)); err != nil {
@ -474,7 +474,6 @@ func (c *ClientConn) mainLoop() {
new(MsgSetColorMapEntries), new(MsgSetColorMapEntries),
new(MsgBell), new(MsgBell),
new(MsgServerCutText), new(MsgServerCutText),
new(MsgServerFence),
} }
for _, msg := range defaultMessages { for _, msg := range defaultMessages {
@ -507,7 +506,7 @@ func (c *ClientConn) mainLoop() {
// Unsupported message type! Bad! // Unsupported message type! Bad!
break break
} }
logger.Debugf("ClientConn.MainLoop: got ServerMessage:%s", common.ServerMessageType(messageType)) logger.Infof("ClientConn.MainLoop: got ServerMessage:%s", common.ServerMessageType(messageType))
reader.SendMessageStart(common.ServerMessageType(messageType)) reader.SendMessageStart(common.ServerMessageType(messageType))
reader.PublishBytes([]byte{byte(messageType)}) reader.PublishBytes([]byte{byte(messageType)})

View File

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
func readPixelFormat(r io.Reader, result *common.PixelFormat) error { func readPixelFormat(r io.Reader, result *common.PixelFormat) error {

View File

@ -6,9 +6,9 @@ import (
"fmt" "fmt"
"io" "io"
"strings" "strings"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/encodings" "vncproxy/encodings"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
// MsgFramebufferUpdate consists of a sequence of rectangles of // MsgFramebufferUpdate consists of a sequence of rectangles of
@ -63,7 +63,7 @@ func (fbm *MsgFramebufferUpdate) Read(c common.IClientConn, r *common.RfbReadHel
// We must always support the raw encoding // We must always support the raw encoding
rawEnc := new(encodings.RawEncoding) rawEnc := new(encodings.RawEncoding)
encMap[rawEnc.Type()] = rawEnc encMap[rawEnc.Type()] = rawEnc
logger.Debugf("MsgFramebufferUpdate.Read: numrects= %d", numRects) logger.Infof("MsgFramebufferUpdate.Read: numrects= %d", numRects)
rects := make([]common.Rectangle, numRects) rects := make([]common.Rectangle, numRects)
for i := uint16(0); i < numRects; i++ { for i := uint16(0); i < numRects; i++ {
@ -90,7 +90,7 @@ func (fbm *MsgFramebufferUpdate) Read(c common.IClientConn, r *common.RfbReadHel
encType := common.EncodingType(encodingTypeInt) encType := common.EncodingType(encodingTypeInt)
logger.Debugf("MsgFramebufferUpdate.Read: rect# %d, rect hdr data: enctype=%s, data: %s", i, encType, string(jBytes)) logger.Infof("MsgFramebufferUpdate.Read: rect# %d, rect hdr data: enctype=%s, data: %s", i, encType, string(jBytes))
enc, supported := encMap[encodingTypeInt] enc, supported := encMap[encodingTypeInt]
if supported { if supported {
var err error var err error
@ -129,7 +129,7 @@ type MsgSetColorMapEntries struct {
} }
func (fbm *MsgSetColorMapEntries) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error { func (fbm *MsgSetColorMapEntries) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error {
reader := common.NewRfbReadHelper(r) reader := &common.RfbReadHelper{Reader: r}
writeTo := &WriteTo{w, "MsgSetColorMapEntries.CopyTo"} writeTo := &WriteTo{w, "MsgSetColorMapEntries.CopyTo"}
reader.Listeners.AddListener(writeTo) reader.Listeners.AddListener(writeTo)
_, err := fbm.Read(c, reader) _, err := fbm.Read(c, reader)
@ -175,9 +175,9 @@ func (m *MsgSetColorMapEntries) Read(c common.IClientConn, r *common.RfbReadHelp
return nil, err return nil, err
} }
} }
// cmap := c.CurrentColorMap() cmap := c.CurrentColorMap()
// // Update the connection's color map // Update the connection's color map
// cmap[result.FirstColor+i] = *color cmap[result.FirstColor+i] = *color
} }
r.SendMessageEnd(common.ServerMessageType(m.Type())) r.SendMessageEnd(common.ServerMessageType(m.Type()))
return &result, nil return &result, nil

View File

@ -2,8 +2,8 @@ package client
import ( import (
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
type WriteTo struct { type WriteTo struct {

View File

@ -18,7 +18,6 @@ const (
PointerEventMsgType PointerEventMsgType
ClientCutTextMsgType ClientCutTextMsgType
ClientFenceMsgType = 248 ClientFenceMsgType = 248
QEMUExtendedKeyEventMsgType = 255
) )
// Color represents a single color in a color map. // Color represents a single color in a color map.
@ -48,8 +47,6 @@ func (cmt ClientMessageType) String() string {
return "FramebufferUpdateRequest" return "FramebufferUpdateRequest"
case KeyEventMsgType: case KeyEventMsgType:
return "KeyEvent" return "KeyEvent"
case QEMUExtendedKeyEventMsgType:
return "QEMUExtendedKeyEvent"
case PointerEventMsgType: case PointerEventMsgType:
return "PointerEvent" return "PointerEvent"
case ClientCutTextMsgType: case ClientCutTextMsgType:

View File

@ -25,6 +25,6 @@ type IServerConn interface {
type IClientConn interface { type IClientConn interface {
CurrentPixelFormat() *PixelFormat CurrentPixelFormat() *PixelFormat
//CurrentColorMap() *ColorMap CurrentColorMap() *ColorMap
Encodings() []IEncoding Encodings() []IEncoding
} }

View File

@ -73,8 +73,6 @@ func (enct EncodingType) String() string {
return "EncJPEGQualityLevelPseudo1" return "EncJPEGQualityLevelPseudo1"
case EncCursorPseudo: case EncCursorPseudo:
return "EncCursorPseudo" return "EncCursorPseudo"
case EncLedStatePseudo:
return "EncLedStatePseudo"
case EncDesktopSizePseudo: case EncDesktopSizePseudo:
return "EncDesktopSizePseudo" return "EncDesktopSizePseudo"
case EncLastRectPseudo: case EncLastRectPseudo:
@ -185,7 +183,6 @@ const (
EncQEMUPointerMotionChangePseudo EncodingType = -257 EncQEMUPointerMotionChangePseudo EncodingType = -257
EncQEMUExtendedKeyEventPseudo EncodingType = -258 EncQEMUExtendedKeyEventPseudo EncodingType = -258
EncTightPng EncodingType = -260 EncTightPng EncodingType = -260
EncLedStatePseudo EncodingType = -261
EncExtendedDesktopSizePseudo EncodingType = -308 EncExtendedDesktopSizePseudo EncodingType = -308
EncXvpPseudo EncodingType = -309 EncXvpPseudo EncodingType = -309
EncFencePseudo EncodingType = -312 EncFencePseudo EncodingType = -312

View File

@ -5,7 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"io" "io"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
var TightMinToCompress = 12 var TightMinToCompress = 12

View File

@ -3,7 +3,7 @@ package encodings
import ( import (
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type CopyRectEncoding struct { type CopyRectEncoding struct {

View File

@ -3,7 +3,7 @@ package encodings
import ( import (
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type CoRREEncoding struct { type CoRREEncoding struct {

View File

@ -3,7 +3,7 @@ package encodings
import ( import (
"io" "io"
"math" "math"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type EncCursorPseudo struct { type EncCursorPseudo struct {

View File

@ -2,8 +2,8 @@ package encodings
import ( import (
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
const ( const (

View File

@ -1,31 +0,0 @@
package encodings
import (
"io"
"github.com/amitbet/vncproxy/common"
"github.com/amitbet/vncproxy/logger"
)
type EncLedStatePseudo struct {
LedState uint8
}
func (pe *EncLedStatePseudo) Type() int32 {
return int32(common.EncLedStatePseudo)
}
func (pe *EncLedStatePseudo) WriteTo(w io.Writer) (n int, err error) {
w.Write([]byte{pe.LedState})
return 1, nil
}
func (pe *EncLedStatePseudo) Read(pf *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.IEncoding, error) {
if rect.Width*rect.Height == 0 {
return pe, nil
}
u8, err := r.ReadUint8()
pe.LedState = u8
if err != nil {
logger.Error("error while reading led state: ", err)
return pe, err
}
return pe, nil
}

View File

@ -2,7 +2,7 @@ package encodings
import ( import (
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type PseudoEncoding struct { type PseudoEncoding struct {

View File

@ -3,7 +3,7 @@ package encodings
import ( import (
"bytes" "bytes"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
// RawEncoding is raw pixel data sent by the server. // RawEncoding is raw pixel data sent by the server.

View File

@ -3,7 +3,7 @@ package encodings
import ( import (
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type RREEncoding struct { type RREEncoding struct {

View File

@ -4,8 +4,8 @@ import (
"bytes" "bytes"
"errors" "errors"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
var TightMinToCompress int = 12 var TightMinToCompress int = 12
@ -142,7 +142,7 @@ func handleTightFilters(subencoding uint8, pixelFmt *common.PixelFormat, rect *c
return return
} }
paletteSize := int(colorCount) + 1 // add one more paletteSize := colorCount + 1 // add one more
logger.Debugf("handleTightFilters: ----PALETTE_FILTER: paletteSize=%d bytesPixel=%d\n", paletteSize, bytesPixel) logger.Debugf("handleTightFilters: ----PALETTE_FILTER: paletteSize=%d bytesPixel=%d\n", paletteSize, bytesPixel)
//complete palette //complete palette
_, err = r.ReadBytes(int(paletteSize) * bytesPixel) _, err = r.ReadBytes(int(paletteSize) * bytesPixel)
@ -155,7 +155,7 @@ func handleTightFilters(subencoding uint8, pixelFmt *common.PixelFormat, rect *c
if paletteSize == 2 { if paletteSize == 2 {
dataLength = int(rect.Height) * ((int(rect.Width) + 7) / 8) dataLength = int(rect.Height) * ((int(rect.Width) + 7) / 8)
} else { } else {
dataLength = int(rect.Width) * int(rect.Height) dataLength = int(rect.Width * rect.Height)
} }
_, err = r.ReadTightData(dataLength) _, err = r.ReadTightData(dataLength)
if err != nil { if err != nil {

View File

@ -3,8 +3,8 @@ package encodings
import ( import (
"fmt" "fmt"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
type TightPngEncoding struct { type TightPngEncoding struct {

View File

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type ZLibEncoding struct { type ZLibEncoding struct {

View File

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type ZRLEEncoding struct { type ZRLEEncoding struct {

3
go.mod
View File

@ -1,3 +0,0 @@
module github.com/amitbet/vncproxy
require golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76

2
go.sum
View File

@ -1,2 +0,0 @@
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 h1:xx5MUFyRQRbPk6VjWjIE1epE/K5AoDD8QUN116NCy8k=
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@ -4,30 +4,6 @@ import "fmt"
var simpleLogger = SimpleLogger{LogLevelInfo} var simpleLogger = SimpleLogger{LogLevelInfo}
func SetLogLevel(logLevel string) {
level := GetLogLevel(logLevel)
fmt.Println("Log level set to: ", logLevel)
simpleLogger = SimpleLogger{level}
}
func GetLogLevel(logLevel string) LogLevel {
switch logLevel {
case "trace":
return LogLevelTrace
case "debug":
return LogLevelDebug
case "info":
return LogLevelInfo
case "warn":
return LogLevelWarn
case "error":
return LogLevelError
case "fatal":
return LogLevelFatal
}
return LogLevelInfo
}
type Logger interface { type Logger interface {
Debug(v ...interface{}) Debug(v ...interface{})
Debugf(format string, v ...interface{}) Debugf(format string, v ...interface{})
@ -151,13 +127,6 @@ func Debugf(format string, v ...interface{}) {
simpleLogger.Debugf(format, v...) simpleLogger.Debugf(format, v...)
} }
func Trace(v ...interface{}) {
simpleLogger.Trace(v...)
}
func Tracef(format string, v ...interface{}) {
simpleLogger.Tracef(format, v...)
}
func Info(v ...interface{}) { func Info(v ...interface{}) {
simpleLogger.Info(v...) simpleLogger.Info(v...)
} }

View File

@ -4,21 +4,19 @@ import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/encodings" "vncproxy/encodings"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
"github.com/amitbet/vncproxy/player" "vncproxy/player"
"github.com/amitbet/vncproxy/server" "vncproxy/server"
) )
func main() { func main() {
wsPort := flag.String("wsPort", "", "websocket port for player to listen to client connections") wsPort := flag.String("wsPort", "", "websocket port for player to listen to client connections")
tcpPort := flag.String("tcpPort", "", "tcp port for player to listen to client connections") tcpPort := flag.String("tcpPort", "", "tcp port for player to listen to client connections")
fbsFile := flag.String("fbsFile", "", "fbs file to serve to all connecting clients") fbsFile := flag.String("fbsFile", "", "fbs file to serve to all connecting clients")
logLevel := flag.String("logLevel", "info", "change logging level")
flag.Parse() flag.Parse()
logger.SetLogLevel(*logLevel)
fmt.Println("**************************************************************************") fmt.Println("**************************************************************************")
fmt.Println("*** This is a toy server that replays a single FBS file to all clients ***") fmt.Println("*** This is a toy server that replays a single FBS file to all clients ***")
@ -82,7 +80,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
url := "http://0.0.0.0:" + *wsPort + "/" url := "http://localhost:" + *wsPort + "/"
if *tcpPort != "" && *wsPort != "" { if *tcpPort != "" && *wsPort != "" {
logger.Infof("running two listeners: tcp port: %s, ws url: %s", *tcpPort, url) logger.Infof("running two listeners: tcp port: %s, ws url: %s", *tcpPort, url)

View File

@ -3,25 +3,17 @@ package player
import ( import (
"encoding/binary" "encoding/binary"
"io"
"time" "time"
"github.com/amitbet/vncproxy/client" "vncproxy/client"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger"
"github.com/amitbet/vncproxy/server"
)
type VncStreamFileReader interface { "vncproxy/logger"
io.Reader "vncproxy/server"
CurrentTimestamp() int )
ReadStartSession() (*common.ServerInit, error)
CurrentPixelFormat() *common.PixelFormat
Encodings() []common.IEncoding
}
type FBSPlayListener struct { type FBSPlayListener struct {
Conn *server.ServerConn Conn *server.ServerConn
Fbs VncStreamFileReader Fbs *FbsReader
serverMessageMap map[uint8]common.ServerMessage serverMessageMap map[uint8]common.ServerMessage
firstSegDone bool firstSegDone bool
startTime int startTime int
@ -96,7 +88,7 @@ func (h *FBSPlayListener) sendFbsMessage() {
return return
} }
timeSinceStart := int(time.Now().UnixNano()/int64(time.Millisecond)) - h.startTime timeSinceStart := int(time.Now().UnixNano()/int64(time.Millisecond)) - h.startTime
timeToSleep := fbs.CurrentTimestamp() - timeSinceStart timeToSleep := fbs.currentTimestamp - timeSinceStart
if timeToSleep > 0 { if timeToSleep > 0 {
time.Sleep(time.Duration(timeToSleep) * time.Millisecond) time.Sleep(time.Duration(timeToSleep) * time.Millisecond)
} }

View File

@ -5,9 +5,9 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"os" "os"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/encodings" "vncproxy/encodings"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
type FbsReader struct { type FbsReader struct {
@ -18,10 +18,6 @@ type FbsReader struct {
encodings []common.IEncoding encodings []common.IEncoding
} }
func (fbs *FbsReader) CurrentTimestamp() int {
return fbs.currentTimestamp
}
func (fbs *FbsReader) Read(p []byte) (n int, err error) { func (fbs *FbsReader) Read(p []byte) (n int, err error) {
if fbs.buffer.Len() < len(p) { if fbs.buffer.Len() < len(p) {
seg, err := fbs.ReadSegment() seg, err := fbs.ReadSegment()
@ -37,8 +33,7 @@ func (fbs *FbsReader) Read(p []byte) (n int, err error) {
} }
func (fbs *FbsReader) CurrentPixelFormat() *common.PixelFormat { return fbs.pixelFormat } func (fbs *FbsReader) CurrentPixelFormat() *common.PixelFormat { return fbs.pixelFormat }
func (fbs *FbsReader) CurrentColorMap() *common.ColorMap { return &common.ColorMap{} }
//func (fbs *FbsReader) CurrentColorMap() *common.ColorMap { return &common.ColorMap{} }
func (fbs *FbsReader) Encodings() []common.IEncoding { return fbs.encodings } func (fbs *FbsReader) Encodings() []common.IEncoding { return fbs.encodings }
func NewFbsReader(fbsFile string) (*FbsReader, error) { func NewFbsReader(fbsFile string) (*FbsReader, error) {
@ -58,7 +53,6 @@ func NewFbsReader(fbsFile string) (*FbsReader, error) {
&encodings.TightEncoding{}, &encodings.TightEncoding{},
&encodings.TightPngEncoding{}, &encodings.TightPngEncoding{},
&encodings.EncCursorPseudo{}, &encodings.EncCursorPseudo{},
&encodings.EncLedStatePseudo{},
&encodings.RawEncoding{}, &encodings.RawEncoding{},
&encodings.RREEncoding{}, &encodings.RREEncoding{},
}, },

View File

@ -3,15 +3,14 @@ package player
import ( import (
"testing" "testing"
"time" "time"
"vncproxy/common"
"github.com/amitbet/vncproxy/common" "vncproxy/encodings"
"github.com/amitbet/vncproxy/encodings" "vncproxy/logger"
"github.com/amitbet/vncproxy/logger" "vncproxy/server"
"github.com/amitbet/vncproxy/server"
) )
func TestServer(t *testing.T) { func TestServer(t *testing.T) {
t.Skip("this isn't an automated test, just an entrypoint for debugging")
//chServer := make(chan common.ClientMessage) //chServer := make(chan common.ClientMessage)
//chClient := make(chan common.ServerMessage) //chClient := make(chan common.ServerMessage)
@ -19,7 +18,6 @@ func TestServer(t *testing.T) {
&encodings.RawEncoding{}, &encodings.RawEncoding{},
&encodings.TightEncoding{}, &encodings.TightEncoding{},
&encodings.EncCursorPseudo{}, &encodings.EncCursorPseudo{},
&encodings.EncLedStatePseudo{},
//encodings.TightPngEncoding{}, //encodings.TightPngEncoding{},
&encodings.RREEncoding{}, &encodings.RREEncoding{},
&encodings.ZLibEncoding{}, &encodings.ZLibEncoding{},

View File

@ -1,13 +1,9 @@
package main package main
import ( import "vncproxy/proxy"
"flag" import "flag"
"os" import "vncproxy/logger"
"path/filepath" import "os"
"github.com/amitbet/vncproxy/logger"
vncproxy "github.com/amitbet/vncproxy/proxy"
)
func main() { func main() {
//create default session if required //create default session if required
@ -15,14 +11,10 @@ func main() {
var wsPort = flag.String("wsPort", "", "websocket port") var wsPort = flag.String("wsPort", "", "websocket port")
var vncPass = flag.String("vncPass", "", "password on incoming vnc connections to the proxy, defaults to no password") var vncPass = flag.String("vncPass", "", "password on incoming vnc connections to the proxy, defaults to no password")
var recordDir = flag.String("recDir", "", "path to save FBS recordings WILL NOT RECORD if not defined.") var recordDir = flag.String("recDir", "", "path to save FBS recordings WILL NOT RECORD if not defined.")
var targetVnc = flag.String("target", "", "target vnc server (host:port or /path/to/unix.socket)") var targetVncPort = flag.String("targPort", "", "target vnc server port")
var targetVncPort = flag.String("targPort", "", "target vnc server port (deprecated, use -target)")
var targetVncHost = flag.String("targHost", "", "target vnc server host (deprecated, use -target)")
var targetVncPass = flag.String("targPass", "", "target vnc password") var targetVncPass = flag.String("targPass", "", "target vnc password")
var logLevel = flag.String("logLevel", "info", "change logging level")
flag.Parse() flag.Parse()
logger.SetLogLevel(*logLevel)
if *tcpPort == "" && *wsPort == "" { if *tcpPort == "" && *wsPort == "" {
logger.Error("no listening port defined") logger.Error("no listening port defined")
@ -30,8 +22,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
if *targetVnc == "" && *targetVncPort == "" { if *targetVncPort == "" {
logger.Error("no target vnc server host/port or socket defined") logger.Error("no target vnc server port defined")
flag.Usage() flag.Usage()
os.Exit(1) os.Exit(1)
} }
@ -39,42 +31,25 @@ func main() {
if *vncPass == "" { if *vncPass == "" {
logger.Warn("proxy will have no password") logger.Warn("proxy will have no password")
} }
if *recordDir == "" {
logger.Warn("FBS recording is turned off")
}
tcpURL := "" proxy := &proxy.VncProxy{
if *tcpPort != "" { WsListeningUrl: "http://localhost:" + string(*wsPort) + "/", // empty = not listening on ws
tcpURL = ":" + string(*tcpPort) RecordingDir: *recordDir, //"/Users/amitbet/vncRec", // empty = no recording
} TcpListeningUrl: ":" + string(*tcpPort),
wsURL := ""
if *wsPort != "" {
wsURL = "http://0.0.0.0:" + string(*wsPort) + "/"
}
proxy := &vncproxy.VncProxy{
WsListeningURL: wsURL, // empty = not listening on ws
TCPListeningURL: tcpURL,
ProxyVncPassword: *vncPass, //empty = no auth ProxyVncPassword: *vncPass, //empty = no auth
SingleSession: &vncproxy.VncSession{ SingleSession: &proxy.VncSession{
Target: *targetVnc, TargetHostname: "localhost",
TargetHostname: *targetVncHost,
TargetPort: *targetVncPort, TargetPort: *targetVncPort,
TargetPassword: *targetVncPass, //"vncPass", TargetPassword: *targetVncPass, //"vncPass",
ID: "dummySession", ID: "dummySession",
Status: vncproxy.SessionStatusInit, Status: proxy.SessionStatusInit,
Type: vncproxy.SessionTypeProxyPass, Type: proxy.SessionTypeRecordingProxy,
}, // to be used when not using sessions }, // to be used when not using sessions
UsingSessions: false, //false = single session - defined in the var above UsingSessions: false, //false = single session - defined in the var above
} }
if *recordDir != "" {
fullPath, err := filepath.Abs(*recordDir)
if err != nil {
logger.Error("bad recording path: ", err)
}
logger.Info("FBS recording is turned on, writing to dir: ", fullPath)
proxy.RecordingDir = fullPath
proxy.SingleSession.Type = vncproxy.SessionTypeRecordingProxy
} else {
logger.Info("FBS recording is turned off")
}
proxy.StartListening() proxy.StartListening()
} }

View File

@ -1,10 +1,10 @@
package proxy package proxy
import ( import (
"github.com/amitbet/vncproxy/client" "vncproxy/client"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
"github.com/amitbet/vncproxy/server" "vncproxy/server"
) )
type ClientUpdater struct { type ClientUpdater struct {
@ -13,7 +13,7 @@ type ClientUpdater struct {
// Consume recieves vnc-server-bound messages (Client messages) and updates the server part of the proxy // Consume recieves vnc-server-bound messages (Client messages) and updates the server part of the proxy
func (cc *ClientUpdater) Consume(seg *common.RfbSegment) error { func (cc *ClientUpdater) Consume(seg *common.RfbSegment) error {
logger.Tracef("ClientUpdater.Consume (vnc-server-bound): got segment type=%s bytes: %v", seg.SegmentType, seg.Bytes) //logger.Debugf("ClientUpdater.Consume (vnc-server-bound): got segment type=%s bytes: %v", seg.SegmentType, seg.Bytes)
switch seg.SegmentType { switch seg.SegmentType {
case common.SegmentFullyParsedClientMessage: case common.SegmentFullyParsedClientMessage:

View File

@ -5,19 +5,18 @@ import (
"path" "path"
"strconv" "strconv"
"time" "time"
"vncproxy/client"
"github.com/amitbet/vncproxy/client" "vncproxy/common"
"github.com/amitbet/vncproxy/common" "vncproxy/encodings"
"github.com/amitbet/vncproxy/encodings" "vncproxy/logger"
"github.com/amitbet/vncproxy/logger" "vncproxy/player"
"github.com/amitbet/vncproxy/player" listeners "vncproxy/recorder"
listeners "github.com/amitbet/vncproxy/recorder" "vncproxy/server"
"github.com/amitbet/vncproxy/server"
) )
type VncProxy struct { type VncProxy struct {
TCPListeningURL string // empty = not listening on tcp TcpListeningUrl string // empty = not listening on tcp
WsListeningURL string // empty = not listening on ws WsListeningUrl string // empty = not listening on ws
RecordingDir string // empty = no recording RecordingDir string // empty = no recording
ProxyVncPassword string //empty = no auth ProxyVncPassword string //empty = no auth
SingleSession *VncSession // to be used when not using sessions SingleSession *VncSession // to be used when not using sessions
@ -25,17 +24,8 @@ type VncProxy struct {
sessionManager *SessionManager sessionManager *SessionManager
} }
func (vp *VncProxy) createClientConnection(target string, vncPass string) (*client.ClientConn, error) { func (vp *VncProxy) createClientConnection(targetServerUrl string, vncPass string) (*client.ClientConn, error) {
var ( nc, err := net.Dial("tcp", targetServerUrl)
nc net.Conn
err error
)
if target[0] == '/' {
nc, err = net.Dial("unix", target)
} else {
nc, err = net.Dial("tcp", target)
}
if err != nil { if err != nil {
logger.Errorf("error connecting to vnc server: %s", err) logger.Errorf("error connecting to vnc server: %s", err)
@ -72,7 +62,7 @@ func (vp *VncProxy) getProxySession(sessionId string) (*VncSession, error) {
} }
func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server.ServerConn) error { func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server.ServerConn) error {
var err error
session, err := vp.getProxySession(sconn.SessionId) session, err := vp.getProxySession(sconn.SessionId)
if err != nil { if err != nil {
logger.Errorf("Proxy.newServerConnHandler can't get session: %d", sconn.SessionId) logger.Errorf("Proxy.newServerConnHandler can't get session: %d", sconn.SessionId)
@ -80,11 +70,10 @@ func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server
} }
var rec *listeners.Recorder var rec *listeners.Recorder
if session.Type == SessionTypeRecordingProxy { if session.Type == SessionTypeRecordingProxy {
recFile := "recording" + strconv.FormatInt(time.Now().Unix(), 10) + ".rbs" recFile := "recording" + strconv.FormatInt(time.Now().Unix(), 10) + ".rbs"
recPath := path.Join(vp.RecordingDir, recFile) recPath := path.Join(vp.RecordingDir, recFile)
rec, err = listeners.NewRecorder(recPath) rec, err := listeners.NewRecorder(recPath)
if err != nil { if err != nil {
logger.Errorf("Proxy.newServerConnHandler can't open recorder save path: %s", recPath) logger.Errorf("Proxy.newServerConnHandler can't open recorder save path: %s", recPath)
return err return err
@ -95,12 +84,7 @@ func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server
session.Status = SessionStatusInit session.Status = SessionStatusInit
if session.Type == SessionTypeProxyPass || session.Type == SessionTypeRecordingProxy { if session.Type == SessionTypeProxyPass || session.Type == SessionTypeRecordingProxy {
target := session.Target cconn, err := vp.createClientConnection(session.TargetHostname+":"+session.TargetPort, session.TargetPassword)
if session.TargetHostname != "" && session.TargetPort != "" {
target = session.TargetHostname + ":" + session.TargetPort
}
cconn, err := vp.createClientConnection(target, session.TargetPassword)
if err != nil { if err != nil {
session.Status = SessionStatusError session.Status = SessionStatusError
logger.Errorf("Proxy.newServerConnHandler error creating connection: %s", err) logger.Errorf("Proxy.newServerConnHandler error creating connection: %s", err)
@ -133,7 +117,6 @@ func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server
&encodings.RawEncoding{}, &encodings.RawEncoding{},
&encodings.TightEncoding{}, &encodings.TightEncoding{},
&encodings.EncCursorPseudo{}, &encodings.EncCursorPseudo{},
&encodings.EncLedStatePseudo{},
&encodings.TightPngEncoding{}, &encodings.TightPngEncoding{},
&encodings.RREEncoding{}, &encodings.RREEncoding{},
&encodings.ZLibEncoding{}, &encodings.ZLibEncoding{},
@ -186,19 +169,19 @@ func (vp *VncProxy) StartListening() {
UseDummySession: !vp.UsingSessions, UseDummySession: !vp.UsingSessions,
} }
if vp.TCPListeningURL != "" && vp.WsListeningURL != "" { if vp.TcpListeningUrl != "" && vp.WsListeningUrl != "" {
logger.Infof("running two listeners: tcp port: %s, ws url: %s", vp.TCPListeningURL, vp.WsListeningURL) logger.Infof("running two listeners: tcp port: %s, ws url: %s", vp.TcpListeningUrl, vp.WsListeningUrl)
go server.WsServe(vp.WsListeningURL, cfg) go server.WsServe(vp.WsListeningUrl, cfg)
server.TcpServe(vp.TCPListeningURL, cfg) server.TcpServe(":"+vp.TcpListeningUrl, cfg)
} }
if vp.WsListeningURL != "" { if vp.WsListeningUrl != "" {
logger.Infof("running ws listener url: %s", vp.WsListeningURL) logger.Infof("running ws listener url: %s", vp.WsListeningUrl)
server.WsServe(vp.WsListeningURL, cfg) server.WsServe(vp.WsListeningUrl, cfg)
} }
if vp.TCPListeningURL != "" { if vp.TcpListeningUrl != "" {
logger.Infof("running tcp listener on port: %s", vp.TCPListeningURL) logger.Infof("running tcp listener on port: %s", vp.TcpListeningUrl)
server.TcpServe(vp.TCPListeningURL, cfg) server.TcpServe(":"+vp.TcpListeningUrl, cfg)
} }
} }

View File

@ -4,18 +4,17 @@ import "testing"
func TestProxy(t *testing.T) { func TestProxy(t *testing.T) {
//create default session if required //create default session if required
t.Skip("this isn't an automated test, just an entrypoint for debugging")
proxy := &VncProxy{ proxy := &VncProxy{
WsListeningURL: "http://0.0.0.0:7778/", // empty = not listening on ws WsListeningUrl: "http://localhost:7777/", // empty = not listening on ws
RecordingDir: "d:\\", // empty = no recording RecordingDir: "/Users/amitbet/vncRec", // empty = no recording
TCPListeningURL: ":5904", TcpListeningUrl: ":5904",
//RecordingDir: "C:\\vncRec", // empty = no recording //recordingDir: "C:\\vncRec", // empty = no recording
ProxyVncPassword: "1234", //empty = no auth ProxyVncPassword: "1234", //empty = no auth
SingleSession: &VncSession{ SingleSession: &VncSession{
TargetHostname: "192.168.1.101", TargetHostname: "localhost",
TargetPort: "5901", TargetPort: "5903",
TargetPassword: "123456", TargetPassword: "Ch_#!T@8",
ID: "dummySession", ID: "dummySession",
Status: SessionStatusInit, Status: SessionStatusInit,
Type: SessionTypeRecordingProxy, Type: SessionTypeRecordingProxy,

View File

@ -16,7 +16,6 @@ const (
) )
type VncSession struct { type VncSession struct {
Target string
TargetHostname string TargetHostname string
TargetPort string TargetPort string
TargetPassword string TargetPassword string

View File

@ -5,31 +5,22 @@ import (
"net" "net"
"os" "os"
"time" "time"
"github.com/amitbet/vncproxy/client" "vncproxy/client"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/encodings" "vncproxy/encodings"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
"github.com/amitbet/vncproxy/recorder" "vncproxy/recorder"
) )
func main() { func main() {
// var tcpPort = flag.String("tcpPort", "", "tcp port") // var tcpPort = flag.String("tcpPort", "", "tcp port")
// var wsPort = flag.String("wsPort", "", "websocket port") // var wsPort = flag.String("wsPort", "", "websocket port")
// var vncPass = flag.String("vncPass", "", "password on incoming vnc connections to the proxy, defaults to no password") // var vncPass = flag.String("vncPass", "", "password on incoming vnc connections to the proxy, defaults to no password")
var recordDir = flag.String("recFile", "", "FBS file to create, recordings WILL NOT RECORD IF EMPTY.") var recordDir = flag.String("recDir", "", "path to save FBS recordings WILL NOT RECORD IF EMPTY.")
var targetVncPort = flag.String("targPort", "", "target vnc server port") var targetVncPort = flag.String("targPort", "", "target vnc server port")
var targetVncPass = flag.String("targPass", "", "target vnc password") var targetVncPass = flag.String("targPass", "", "target vnc password")
var targetVncHost = flag.String("targHost", "localhost", "target vnc hostname")
var logLevel = flag.String("logLevel", "info", "change logging level")
flag.Parse() flag.Parse()
logger.SetLogLevel(*logLevel)
if *targetVncHost == "" {
logger.Error("no target vnc server host defined")
flag.Usage()
os.Exit(1)
}
if *targetVncPort == "" { if *targetVncPort == "" {
logger.Error("no target vnc server port defined") logger.Error("no target vnc server port defined")
@ -42,12 +33,10 @@ func main() {
} }
if *recordDir == "" { if *recordDir == "" {
logger.Warn("FBS recording is turned off") logger.Warn("FBS recording is turned off")
} else {
logger.Infof("Recording rfb stream into file: '%s'", *recordDir)
} }
//nc, err := net.Dial("tcp", "192.168.1.101:5903") //nc, err := net.Dial("tcp", "192.168.1.101:5903")
nc, err := net.Dial("tcp", *targetVncHost+":"+*targetVncPort) nc, err := net.Dial("tcp", "localhost:"+*targetVncPort)
if err != nil { if err != nil {
logger.Errorf("error connecting to vnc server: %s", err) logger.Errorf("error connecting to vnc server: %s", err)
@ -85,9 +74,9 @@ func main() {
encs := []common.IEncoding{ encs := []common.IEncoding{
&encodings.TightEncoding{}, &encodings.TightEncoding{},
//&encodings.TightPngEncoding{}, //&encodings.TightPngEncoding{},
//&encodings.RREEncoding{}, //rre := encodings.RREEncoding{},
//&encodings.ZLibEncoding{}, //zlib := encodings.ZLibEncoding{},
//&encodings.ZRLEEncoding{}, //zrle := encodings.ZRLEEncoding{},
//&encodings.CopyRectEncoding{}, //&encodings.CopyRectEncoding{},
//coRRE := encodings.CoRREEncoding{}, //coRRE := encodings.CoRREEncoding{},
//hextile := encodings.HextileEncoding{}, //hextile := encodings.HextileEncoding{},

View File

@ -5,9 +5,9 @@ import (
"encoding/binary" "encoding/binary"
"os" "os"
"time" "time"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
"github.com/amitbet/vncproxy/server" "vncproxy/server"
) )
type Recorder struct { type Recorder struct {
@ -38,7 +38,7 @@ func NewRecorder(saveFilePath string) (*Recorder, error) {
rec.maxWriteSize = 65535 rec.maxWriteSize = 65535
rec.writer, err = os.OpenFile(saveFilePath, os.O_RDWR|os.O_CREATE, 0644) rec.writer, err = os.OpenFile(saveFilePath, os.O_RDWR|os.O_CREATE, 0755)
if err != nil { if err != nil {
logger.Errorf("unable to open file: %s, error: %v", saveFilePath, err) logger.Errorf("unable to open file: %s, error: %v", saveFilePath, err)
return nil, err return nil, err

View File

@ -2,9 +2,9 @@ package recorder
import ( import (
"time" "time"
"github.com/amitbet/vncproxy/client" "vncproxy/client"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
type RfbRequester struct { type RfbRequester struct {

View File

@ -3,7 +3,7 @@ package server
import ( import (
"encoding/binary" "encoding/binary"
"io" "io"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
// Key represents a VNC key press. // Key represents a VNC key press.
@ -165,36 +165,6 @@ func (msg *MsgKeyEvent) Write(c io.Writer) error {
return nil return nil
} }
// MsgKeyEvent holds the wire format message.
type MsgQEMUExtKeyEvent struct {
SubmessageType uint8 // submessage type
DownFlag uint16 // down-flag
KeySym Key // key symbol
KeyCode uint32 // scan code
}
func (*MsgQEMUExtKeyEvent) Type() common.ClientMessageType {
return common.QEMUExtendedKeyEventMsgType
}
func (*MsgQEMUExtKeyEvent) Read(c io.Reader) (common.ClientMessage, error) {
msg := MsgKeyEvent{}
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
return nil, err
}
return &msg, nil
}
func (msg *MsgQEMUExtKeyEvent) Write(c io.Writer) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
}
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
return err
}
return nil
}
// PointerEventMessage holds the wire format message. // PointerEventMessage holds the wire format message.
type MsgPointerEvent struct { type MsgPointerEvent struct {
Mask uint8 // button-mask Mask uint8 // button-mask
@ -310,34 +280,3 @@ func (msg *MsgClientCutText) Write(c io.Writer) error {
return nil return nil
} }
// MsgClientQemuExtendedKey holds the wire format message, for qemu keys
type MsgClientQemuExtendedKey struct {
SubType uint8 // sub type
IsDown uint16 // button down indicator
KeySym uint32 // key symbol
KeyCode uint32 // key code
}
func (*MsgClientQemuExtendedKey) Type() common.ClientMessageType {
return common.QEMUExtendedKeyEventMsgType
}
func (*MsgClientQemuExtendedKey) Read(c io.Reader) (common.ClientMessage, error) {
msg := MsgClientQemuExtendedKey{}
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
return nil, err
}
return &msg, nil
}
func (msg *MsgClientQemuExtendedKey) Write(c io.Writer) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
}
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
return err
}
return nil
}

View File

@ -3,10 +3,10 @@ package server
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"io" "io"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
const ProtoVersionLength = 12 const ProtoVersionLength = 12
@ -95,7 +95,7 @@ func ServerSecurityHandler(cfg *ServerConfig, c *ServerConn) error {
sType, ok := secTypes[secType] sType, ok := secTypes[secType]
if !ok { if !ok {
return fmt.Errorf("server type %d not implemented", secType) return fmt.Errorf("server type %d not implemented")
} }
var authCode uint32 var authCode uint32
@ -135,7 +135,7 @@ func ServerServerInitHandler(cfg *ServerConfig, c *ServerConn) error {
NameLength: uint32(len(cfg.DesktopName)), NameLength: uint32(len(cfg.DesktopName)),
NameText: []byte(cfg.DesktopName), NameText: []byte(cfg.DesktopName),
} }
logger.Debugf("Server.ServerServerInitHandler initMessage: %v", srvInit) logger.Infof("Server.ServerServerInitHandler initMessage: %v", srvInit)
if err := binary.Write(c, binary.BigEndian, srvInit.FBWidth); err != nil { if err := binary.Write(c, binary.BigEndian, srvInit.FBWidth); err != nil {
return err return err
} }

View File

@ -6,7 +6,7 @@ import (
"crypto/rand" "crypto/rand"
"errors" "errors"
"log" "log"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
type SecurityType uint8 type SecurityType uint8

View File

@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"io" "io"
"sync" "sync"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
) )
type ServerConn struct { type ServerConn struct {
@ -168,17 +168,16 @@ func (c *ServerConn) handle() error {
default: default:
var messageType common.ClientMessageType var messageType common.ClientMessageType
if err := binary.Read(c, binary.BigEndian, &messageType); err != nil { if err := binary.Read(c, binary.BigEndian, &messageType); err != nil {
logger.Errorf("ServerConn.handle error: %v", err) logger.Errorf("IServerConn.handle error: %v", err)
return err return err
} }
logger.Debugf("ServerConn.handle: got messagetype, %d", messageType)
msg, ok := clientMessages[messageType] msg, ok := clientMessages[messageType]
logger.Debugf("ServerConn.handle: found message type, %v", ok)
if !ok { if !ok {
logger.Errorf("ServerConn.handle: unsupported message-type: %v", messageType) return fmt.Errorf("IServerConn.Handle: unsupported message-type: %v", messageType)
} }
parsedMsg, err := msg.Read(c) parsedMsg, err := msg.Read(c)
logger.Debugf("ServerConn.handle: got parsed messagetype, %v", parsedMsg)
//update connection for pixel format / color map changes //update connection for pixel format / color map changes
switch parsedMsg.Type() { switch parsedMsg.Type() {
case common.SetPixelFormatMsgType: case common.SetPixelFormatMsgType:
@ -197,7 +196,7 @@ func (c *ServerConn) handle() error {
return err return err
} }
logger.Debugf("IServerConn.Handle got ClientMessage: %s, %v", parsedMsg.Type(), parsedMsg) logger.Infof("IServerConn.Handle got ClientMessage: %s, %v", parsedMsg.Type(), parsedMsg)
//TODO: treat set encodings by allowing only supported encoding in proxy configurations //TODO: treat set encodings by allowing only supported encoding in proxy configurations
//// if parsedMsg.Type() == common.SetEncodingsMsgType{ //// if parsedMsg.Type() == common.SetEncodingsMsgType{
//// c.cfg.Encodings //// c.cfg.Encodings

View File

@ -5,7 +5,7 @@ import (
"io" "io"
"log" "log"
"net" "net"
"github.com/amitbet/vncproxy/common" "vncproxy/common"
) )
var DefaultClientMessages = []common.ClientMessage{ var DefaultClientMessages = []common.ClientMessage{
@ -15,7 +15,6 @@ var DefaultClientMessages = []common.ClientMessage{
&MsgKeyEvent{}, &MsgKeyEvent{},
&MsgPointerEvent{}, &MsgPointerEvent{},
&MsgClientCutText{}, &MsgClientCutText{},
&MsgClientQemuExtendedKey{},
} }
// FramebufferUpdate holds a FramebufferUpdate wire format message. // FramebufferUpdate holds a FramebufferUpdate wire format message.

View File

@ -3,9 +3,8 @@ package server
import ( import (
"log" "log"
"testing" "testing"
"vncproxy/common"
"github.com/amitbet/vncproxy/common" "vncproxy/encodings"
"github.com/amitbet/vncproxy/encodings"
) )
func newServerConnHandler(cfg *ServerConfig, conn *ServerConn) error { func newServerConnHandler(cfg *ServerConfig, conn *ServerConn) error {
@ -14,7 +13,6 @@ func newServerConnHandler(cfg *ServerConfig, conn *ServerConn) error {
} }
func TestServer(t *testing.T) { func TestServer(t *testing.T) {
t.Skip("this isn't an automated test, just an entrypoint for debugging")
//chServer := make(chan common.ClientMessage) //chServer := make(chan common.ClientMessage)
chClient := make(chan common.ServerMessage) chClient := make(chan common.ServerMessage)

View File

@ -4,7 +4,7 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"github.com/amitbet/vncproxy/logger" "vncproxy/logger"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )

View File

@ -7,10 +7,3 @@
* move encodings to be on the framebufferupdate message object * move encodings to be on the framebufferupdate message object
* clear all messages read functions from updating stuff, move modification logic to another listener * clear all messages read functions from updating stuff, move modification logic to another listener
* message read function should accept only an io.Reader, move read helper logic (readuint8) to an actual helper class * message read function should accept only an io.Reader, move read helper logic (readuint8) to an actual helper class
* new recording format:
* rfb extension
* save FBResponse messages with additional fields
* timestamp
* is incremental
* size (bytes)
* have a header which contains an index of messages, holding timestamps & file positions for seeking