mirror of
https://github.com/amitbet/vncproxy.git
synced 2026-07-15 06:45:04 +00:00
Compare commits
1 Commits
1.11
...
keyframes_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bce301125 |
@@ -3,7 +3,7 @@ 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
|
||||||
@@ -11,7 +11,7 @@ An RFB proxy, written in go that can save and replay FBS files
|
|||||||
- Tested on tight encoding with:
|
- 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)
|
||||||
@@ -23,9 +23,9 @@ An RFB proxy, written in go that can save and replay FBS files
|
|||||||
* player - a toy player that will replay a given fbs file to all incoming connections
|
* player - a toy player that will replay a given fbs file to all incoming connections
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
recorder -recFile=./recording.rbs -targHost=192.168.0.100 -targPort=5903 -targPass=@@@@@
|
recorder -recDir=./recording.rbs -targHost=192.168.0.100 -targPort=5903 -targPass=@@@@@
|
||||||
player -fbsFile=./myrec.fbs -tcpPort=5905
|
player -fbsFile=./myrec.fbs -tcpPort=5905
|
||||||
proxy -recDir=./recordings/ -targHost=192.168.0.100 -targPort=5903 -targPass=@@@@@ -tcpPort=5903 -wsPort=5905 -vncPass=@!@!@!
|
proxy -recDir=./recordings/ -targHost=192.168.0.100 -targPort=5903 -targPass=@@@@@ -tcpPort=5903 -vncPass=@!@!@!
|
||||||
|
|
||||||
### Code usage examples
|
### Code usage examples
|
||||||
* player/main.go (fbs recording vnc client)
|
* player/main.go (fbs recording vnc client)
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -2,7 +2,7 @@
|
|||||||
sum="sha1sum"
|
sum="sha1sum"
|
||||||
|
|
||||||
# VERSION=`date -u +%Y%m%d`
|
# VERSION=`date -u +%Y%m%d`
|
||||||
VERSION="v1.11"
|
VERSION="v1.02"
|
||||||
LDFLAGS="-X main.VERSION=$VERSION -s -w"
|
LDFLAGS="-X main.VERSION=$VERSION -s -w"
|
||||||
GCFLAGS=""
|
GCFLAGS=""
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"unicode"
|
"unicode"
|
||||||
"github.com/amitbet/vncproxy/common"
|
"vncproxy/common"
|
||||||
"github.com/amitbet/vncproxy/logger"
|
"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.
|
||||||
@@ -506,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)})
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ package encodings
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"github.com/amitbet/vncproxy/common"
|
"vncproxy/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PseudoEncoding struct {
|
type PseudoEncoding struct {
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
3
go.mod
@@ -1,3 +0,0 @@
|
|||||||
module github.com/amitbet/vncproxy
|
|
||||||
|
|
||||||
require golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76
|
|
||||||
2
go.sum
2
go.sum
@@ -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=
|
|
||||||
@@ -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...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ***")
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import (
|
|||||||
|
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
"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 VncStreamFileReader interface {
|
type VncStreamFileReader interface {
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -58,7 +58,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{},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package player
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"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/server"
|
"vncproxy/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServer(t *testing.T) {
|
func TestServer(t *testing.T) {
|
||||||
@@ -18,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{},
|
||||||
|
|||||||
199
player/rfb-reader.go
Normal file
199
player/rfb-reader.go
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
package player
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"vncproxy/common"
|
||||||
|
"vncproxy/encodings"
|
||||||
|
"vncproxy/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RfbReader struct {
|
||||||
|
reader io.Reader
|
||||||
|
buffer bytes.Buffer
|
||||||
|
currentTimestamp int
|
||||||
|
pixelFormat *common.PixelFormat
|
||||||
|
encodings []common.IEncoding
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
** RFB File documentation:
|
||||||
|
** Sections:
|
||||||
|
** 0. header:
|
||||||
|
* index seek position
|
||||||
|
*
|
||||||
|
** 1. init message
|
||||||
|
** 2. content
|
||||||
|
* frame message:
|
||||||
|
* size, timestamp, type, content
|
||||||
|
** 3. index:
|
||||||
|
* each frame message start position, full/incremental, timestamp
|
||||||
|
*
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
func (rfb *RfbReader) CurrentTimestamp() int {
|
||||||
|
return rfb.currentTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rfb *RfbReader) Read(p []byte) (n int, err error) {
|
||||||
|
if rfb.buffer.Len() < len(p) {
|
||||||
|
seg, err := rfb.ReadSegment()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.Read: error reading rfbsegment: ", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
rfb.buffer.Write(seg.bytes)
|
||||||
|
rfb.currentTimestamp = int(seg.timestamp)
|
||||||
|
}
|
||||||
|
return rfb.buffer.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rfb *RfbReader) CurrentPixelFormat() *common.PixelFormat { return rfb.pixelFormat }
|
||||||
|
|
||||||
|
//func (rfb *rfbReader) CurrentColorMap() *common.ColorMap { return &common.ColorMap{} }
|
||||||
|
func (rfb *RfbReader) Encodings() []common.IEncoding { return rfb.encodings }
|
||||||
|
|
||||||
|
func NewRfbReader(rfbFile string) (*RfbReader, error) {
|
||||||
|
|
||||||
|
reader, err := os.OpenFile(rfbFile, os.O_RDONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("NewrfbReader: can't open rfb file: ", rfbFile)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RfbReader{reader: reader,
|
||||||
|
encodings: []common.IEncoding{
|
||||||
|
&encodings.CopyRectEncoding{},
|
||||||
|
&encodings.ZLibEncoding{},
|
||||||
|
&encodings.ZRLEEncoding{},
|
||||||
|
&encodings.CoRREEncoding{},
|
||||||
|
&encodings.HextileEncoding{},
|
||||||
|
&encodings.TightEncoding{},
|
||||||
|
&encodings.TightPngEncoding{},
|
||||||
|
&encodings.EncCursorPseudo{},
|
||||||
|
&encodings.RawEncoding{},
|
||||||
|
&encodings.RREEncoding{},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rfb *RfbReader) ReadStartSession() (*common.ServerInit, error) {
|
||||||
|
|
||||||
|
initMsg := common.ServerInit{}
|
||||||
|
reader := rfb.reader
|
||||||
|
|
||||||
|
var framebufferWidth uint16
|
||||||
|
var framebufferHeight uint16
|
||||||
|
var SecTypeNone uint32
|
||||||
|
//read rfb header information (the only part done without the [size|data|timestamp] block wrapper)
|
||||||
|
//.("rfb 001.000\n")
|
||||||
|
bytes := make([]byte, 12)
|
||||||
|
_, err := reader.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init message - rfb file Version:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the version message into the buffer so it will be written in the first rbs block
|
||||||
|
//RFB 003.008\n
|
||||||
|
bytes = make([]byte, 12)
|
||||||
|
_, err = rfb.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - RFB Version: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//push sec type and fb dimensions
|
||||||
|
binary.Read(rfb, binary.BigEndian, &SecTypeNone)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - SecType: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//read frame buffer width, height
|
||||||
|
binary.Read(rfb, binary.BigEndian, &framebufferWidth)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - FBWidth: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
initMsg.FBWidth = framebufferWidth
|
||||||
|
|
||||||
|
binary.Read(rfb, binary.BigEndian, &framebufferHeight)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - FBHeight: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
initMsg.FBHeight = framebufferHeight
|
||||||
|
|
||||||
|
//read pixel format
|
||||||
|
pixelFormat := &common.PixelFormat{}
|
||||||
|
binary.Read(rfb, binary.BigEndian, pixelFormat)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - Pixelformat: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
initMsg.PixelFormat = *pixelFormat
|
||||||
|
//read padding
|
||||||
|
bytes = make([]byte, 3)
|
||||||
|
rfb.Read(bytes)
|
||||||
|
rfb.pixelFormat = pixelFormat
|
||||||
|
|
||||||
|
//read desktop name
|
||||||
|
var desknameLen uint32
|
||||||
|
binary.Read(rfb, binary.BigEndian, &desknameLen)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - deskname Len: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
initMsg.NameLength = desknameLen
|
||||||
|
|
||||||
|
bytes = make([]byte, desknameLen)
|
||||||
|
rfb.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: error reading rbs init - desktopName: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
initMsg.NameText = bytes
|
||||||
|
|
||||||
|
return &initMsg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rfb *RfbReader) ReadSegment() (*FbsSegment, error) {
|
||||||
|
reader := rfb.reader
|
||||||
|
var bytesLen uint32
|
||||||
|
|
||||||
|
//read length
|
||||||
|
err := binary.Read(reader, binary.BigEndian, &bytesLen)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadStartSession: read len, error reading rbs file: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
paddedSize := (bytesLen + 3) & 0x7FFFFFFC
|
||||||
|
|
||||||
|
//read bytes
|
||||||
|
bytes := make([]byte, paddedSize)
|
||||||
|
_, err = reader.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadSegment: read bytes, error reading rbs file: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove padding
|
||||||
|
actualBytes := bytes[:bytesLen]
|
||||||
|
|
||||||
|
//read timestamp
|
||||||
|
var timeSinceStart uint32
|
||||||
|
binary.Read(reader, binary.BigEndian, &timeSinceStart)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rfbReader.ReadSegment: read timestamp, error reading rbs file: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//timeStamp := time.Unix(timeSinceStart, 0)
|
||||||
|
seg := &FbsSegment{bytes: actualBytes, timestamp: timeSinceStart}
|
||||||
|
return seg, nil
|
||||||
|
}
|
||||||
@@ -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,11 @@ 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")
|
||||||
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 +23,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 +32,30 @@ 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 := ""
|
tcpUrl := ""
|
||||||
if *tcpPort != "" {
|
if *tcpPort != "" {
|
||||||
tcpURL = ":" + string(*tcpPort)
|
tcpUrl = ":" + string(*tcpPort)
|
||||||
}
|
}
|
||||||
wsURL := ""
|
|
||||||
if *wsPort != "" {
|
proxy := &proxy.VncProxy{
|
||||||
wsURL = "http://0.0.0.0:" + string(*wsPort) + "/"
|
WsListeningUrl: "http://0.0.0.0:" + string(*wsPort) + "/", // empty = not listening on ws
|
||||||
}
|
RecordingDir: *recordDir, //"/Users/amitbet/vncRec", // empty = no recording
|
||||||
proxy := &vncproxy.VncProxy{
|
TcpListeningUrl: tcpUrl,
|
||||||
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: *targetVncHost,
|
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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -95,12 +85,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 +118,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 +170,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -5,25 +5,23 @@ 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 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 == "" {
|
if *targetVncHost == "" {
|
||||||
logger.Error("no target vnc server host defined")
|
logger.Error("no target vnc server host defined")
|
||||||
@@ -42,8 +40,6 @@ 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")
|
||||||
@@ -71,7 +67,11 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
clientConn.Listeners.AddListener(rec)
|
clientConn.Listeners.AddListener(rec)
|
||||||
clientConn.Listeners.AddListener(&recorder.RfbRequester{Conn: clientConn, Name: "Rfb Requester"})
|
clientConn.Listeners.AddListener(&recorder.RfbRequester{
|
||||||
|
Conn: clientConn,
|
||||||
|
Name: "Rfb Requester",
|
||||||
|
FullScreenRefreshInSec: 30, //create a full refresh key frame every 30sec for seeking
|
||||||
|
})
|
||||||
clientConn.Connect()
|
clientConn.Connect()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -189,6 +189,11 @@ func (r *Recorder) writeToDisk() error {
|
|||||||
paddedSize := (bytesLen + 3) & 0x7FFFFFFC
|
paddedSize := (bytesLen + 3) & 0x7FFFFFFC
|
||||||
paddingSize := paddedSize - bytesLen
|
paddingSize := paddedSize - bytesLen
|
||||||
|
|
||||||
|
/// KeyFramePos, _ := r.writer.Seek(0, os.SEEK_CUR)
|
||||||
|
/// fi, err := r.writer.Stat()
|
||||||
|
/// KeyFramePos := fi.Size() + KeyFramePosInBuffer
|
||||||
|
// now save the KF pos in some file
|
||||||
|
|
||||||
//logger.Debugf("paddedSize=%d paddingSize=%d bytesLen=%d", paddedSize, paddingSize, bytesLen)
|
//logger.Debugf("paddedSize=%d paddingSize=%d bytesLen=%d", paddedSize, paddingSize, bytesLen)
|
||||||
//write buffer padded to 32bit
|
//write buffer padded to 32bit
|
||||||
_, err := r.buffer.WriteTo(r.writer)
|
_, err := r.buffer.WriteTo(r.writer)
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ 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 {
|
||||||
Conn *client.ClientConn
|
Conn *client.ClientConn
|
||||||
Name string
|
Name string
|
||||||
Width uint16
|
Width uint16
|
||||||
Height uint16
|
Height uint16
|
||||||
lastRequestTime time.Time
|
lastRequestTime time.Time
|
||||||
|
nextFullScreenRefresh time.Time
|
||||||
|
FullScreenRefreshInSec int // refresh interval (creates keyframes) if 0, disables keyframe creation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RfbRequester) Consume(seg *common.RfbSegment) error {
|
func (p *RfbRequester) Consume(seg *common.RfbSegment) error {
|
||||||
@@ -29,6 +31,7 @@ func (p *RfbRequester) Consume(seg *common.RfbSegment) error {
|
|||||||
p.Height = serverInitMessage.FBHeight
|
p.Height = serverInitMessage.FBHeight
|
||||||
p.lastRequestTime = time.Now()
|
p.lastRequestTime = time.Now()
|
||||||
p.Conn.FramebufferUpdateRequest(false, 0, 0, p.Width, p.Height)
|
p.Conn.FramebufferUpdateRequest(false, 0, 0, p.Width, p.Height)
|
||||||
|
p.nextFullScreenRefresh = time.Now().Add(time.Duration(p.FullScreenRefreshInSec) * time.Second)
|
||||||
|
|
||||||
case common.SegmentMessageStart:
|
case common.SegmentMessageStart:
|
||||||
case common.SegmentRectSeparator:
|
case common.SegmentRectSeparator:
|
||||||
@@ -39,7 +42,20 @@ func (p *RfbRequester) Consume(seg *common.RfbSegment) error {
|
|||||||
// timeForNextReq := p.lastRequestTime.Unix() + minTimeBetweenReq.Nanoseconds()/1000
|
// timeForNextReq := p.lastRequestTime.Unix() + minTimeBetweenReq.Nanoseconds()/1000
|
||||||
// if seg.UpcomingObjectType == int(common.FramebufferUpdate) && time.Now().Unix() > timeForNextReq {
|
// if seg.UpcomingObjectType == int(common.FramebufferUpdate) && time.Now().Unix() > timeForNextReq {
|
||||||
//time.Sleep(300 * time.Millisecond)
|
//time.Sleep(300 * time.Millisecond)
|
||||||
p.Conn.FramebufferUpdateRequest(true, 0, 0, p.Width, p.Height)
|
p.lastRequestTime = time.Now()
|
||||||
|
incremental := true
|
||||||
|
|
||||||
|
if p.FullScreenRefreshInSec > 0 {
|
||||||
|
// if p.nextFullScreenRefresh.IsZero() {
|
||||||
|
// p.nextFullScreenRefresh = time.Now().Add(time.Duration(p.FullScreenRefreshInSec) * time.Second)
|
||||||
|
// }
|
||||||
|
if time.Now().Sub(p.nextFullScreenRefresh) <= 0 {
|
||||||
|
logger.Warn(">>Creating keyframe")
|
||||||
|
p.nextFullScreenRefresh = time.Now().Add(time.Duration(p.FullScreenRefreshInSec) * time.Second)
|
||||||
|
incremental = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.Conn.FramebufferUpdateRequest(incremental, 0, 0, p.Width, p.Height)
|
||||||
//}
|
//}
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -310,34 +310,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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package server
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
"github.com/amitbet/vncproxy/common"
|
"vncproxy/common"
|
||||||
"github.com/amitbet/vncproxy/encodings"
|
"vncproxy/encodings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newServerConnHandler(cfg *ServerConfig, conn *ServerConn) error {
|
func newServerConnHandler(cfg *ServerConfig, conn *ServerConn) error {
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user