mirror of
https://github.com/amitbet/vncproxy.git
synced 2025-08-11 02:21:45 +00:00
added a vnc server and the required client messages parsers.
now I should get to tying up the proxying connections and checking what should be written to the file. (server init?)
This commit is contained in:
parent
007e748c61
commit
66c322c164
@ -1 +0,0 @@
|
|||||||
vncproxy
|
|
@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<resourceExtensions />
|
|
||||||
<wildcardResourcePatterns>
|
|
||||||
<entry name="!?*.java" />
|
|
||||||
<entry name="!?*.form" />
|
|
||||||
<entry name="!?*.class" />
|
|
||||||
<entry name="!?*.groovy" />
|
|
||||||
<entry name="!?*.scala" />
|
|
||||||
<entry name="!?*.flex" />
|
|
||||||
<entry name="!?*.kt" />
|
|
||||||
<entry name="!?*.clj" />
|
|
||||||
<entry name="!?*.aj" />
|
|
||||||
</wildcardResourcePatterns>
|
|
||||||
<annotationProcessing>
|
|
||||||
<profile default="true" name="Default" enabled="false">
|
|
||||||
<processorPath useClasspath="true" />
|
|
||||||
</profile>
|
|
||||||
</annotationProcessing>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,3 +0,0 @@
|
|||||||
<component name="CopyrightManager">
|
|
||||||
<settings default="" />
|
|
||||||
</component>
|
|
@ -6,11 +6,14 @@
|
|||||||
<root url="file://$PROJECT_DIR$/../vncproxy1" />
|
<root url="file://$PROJECT_DIR$/../vncproxy1" />
|
||||||
<root url="file://$PROJECT_DIR$/../GoProjExample" />
|
<root url="file://$PROJECT_DIR$/../GoProjExample" />
|
||||||
<root url="file://$PROJECT_DIR$/../srf.opb" />
|
<root url="file://$PROJECT_DIR$/../srf.opb" />
|
||||||
|
<root url="file://$PROJECT_DIR$/../vshpere-cli" />
|
||||||
<root url="file://$PROJECT_DIR$/../sourcegraph.com" />
|
<root url="file://$PROJECT_DIR$/../sourcegraph.com" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" />
|
||||||
<root url="file://$PROJECT_DIR$/../github.com" />
|
<root url="file://$PROJECT_DIR$/../github.com" />
|
||||||
|
<root url="file://$PROJECT_DIR$/../experience.center.opb" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" />
|
||||||
<root url="file://$PROJECT_DIR$/../golang.org" />
|
<root url="file://$PROJECT_DIR$/../golang.org" />
|
||||||
|
<root url="file://$PROJECT_DIR$/../srf-test-exporter" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/version" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/version" />
|
||||||
@ -24,11 +27,14 @@
|
|||||||
<root url="file://$PROJECT_DIR$/../vncproxy1" />
|
<root url="file://$PROJECT_DIR$/../vncproxy1" />
|
||||||
<root url="file://$PROJECT_DIR$/../GoProjExample" />
|
<root url="file://$PROJECT_DIR$/../GoProjExample" />
|
||||||
<root url="file://$PROJECT_DIR$/../srf.opb" />
|
<root url="file://$PROJECT_DIR$/../srf.opb" />
|
||||||
|
<root url="file://$PROJECT_DIR$/../vshpere-cli" />
|
||||||
<root url="file://$PROJECT_DIR$/../sourcegraph.com" />
|
<root url="file://$PROJECT_DIR$/../sourcegraph.com" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" />
|
||||||
<root url="file://$PROJECT_DIR$/../github.com" />
|
<root url="file://$PROJECT_DIR$/../github.com" />
|
||||||
|
<root url="file://$PROJECT_DIR$/../experience.center.opb" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" />
|
||||||
<root url="file://$PROJECT_DIR$/../golang.org" />
|
<root url="file://$PROJECT_DIR$/../golang.org" />
|
||||||
|
<root url="file://$PROJECT_DIR$/../srf-test-exporter" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" />
|
||||||
<root url="file://$USER_HOME$/srf/experience.center.opb/src/version" />
|
<root url="file://$USER_HOME$/srf/experience.center.opb/src/version" />
|
||||||
|
@ -1,4 +1,30 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="GOROOT" path="/usr/local/Cellar/go/1.8.3/libexec" />
|
<component name="GOROOT" path="/usr/local/Cellar/go/1.8.3/libexec" />
|
||||||
|
<component name="MavenImportPreferences">
|
||||||
|
<option name="generalSettings">
|
||||||
|
<MavenGeneralSettings>
|
||||||
|
<option name="mavenHome" value="Bundled (Maven 3)" />
|
||||||
|
</MavenGeneralSettings>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="true">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
<component name="masterDetails">
|
||||||
|
<states>
|
||||||
|
<state key="ProjectJDKs.UI">
|
||||||
|
<settings>
|
||||||
|
<last-edited>1.8</last-edited>
|
||||||
|
<splitter-proportions>
|
||||||
|
<option name="proportions">
|
||||||
|
<list>
|
||||||
|
<option value="0.2" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</splitter-proportions>
|
||||||
|
</settings>
|
||||||
|
</state>
|
||||||
|
</states>
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
@ -2,7 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/vncproxy.iml" filepath="$PROJECT_DIR$/.idea/vncproxy.iml" />
|
<module fileurl="file://$PROJECT_DIR$/vncproxy.iml" filepath="$PROJECT_DIR$/vncproxy.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="GOPATH <vncproxy>" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
|
|
1536
.idea/workspace.xml
1536
.idea/workspace.xml
File diff suppressed because it is too large
Load Diff
25
.vscode/launch.json
vendored
25
.vscode/launch.json
vendored
@ -8,7 +8,7 @@
|
|||||||
"mode": "test",
|
"mode": "test",
|
||||||
"remotePath": "",
|
"remotePath": "",
|
||||||
"port": 2345,
|
"port": 2345,
|
||||||
"program": "${workspaceRoot}/reader",
|
"program": "${workspaceRoot}/server",
|
||||||
"args": [
|
"args": [
|
||||||
"-test.v"
|
"-test.v"
|
||||||
],
|
],
|
||||||
@ -23,29 +23,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"showLog": true
|
"showLog": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Launch Grouper Tests",
|
|
||||||
"type": "go",
|
|
||||||
"request": "launch",
|
|
||||||
"mode": "test",
|
|
||||||
"remotePath": "",
|
|
||||||
"port": 2345,
|
|
||||||
"program": "${workspaceRoot}/consumer",
|
|
||||||
"args": [
|
|
||||||
"-test.v"
|
|
||||||
],
|
|
||||||
"osx": {
|
|
||||||
"env": {
|
|
||||||
//"GOPATH": "${env.HOME}/Dropbox/go"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"windows": {
|
|
||||||
"env": {
|
|
||||||
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"showLog": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Launch",
|
"name": "Launch",
|
||||||
|
58
common/client-message.go
Normal file
58
common/client-message.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientMessageType uint8
|
||||||
|
|
||||||
|
//go:generate stringer -type=ClientMessageType
|
||||||
|
|
||||||
|
// Client-to-Server message types.
|
||||||
|
const (
|
||||||
|
SetPixelFormatMsgType ClientMessageType = iota
|
||||||
|
_
|
||||||
|
SetEncodingsMsgType
|
||||||
|
FramebufferUpdateRequestMsgType
|
||||||
|
KeyEventMsgType
|
||||||
|
PointerEventMsgType
|
||||||
|
ClientCutTextMsgType
|
||||||
|
)
|
||||||
|
|
||||||
|
// Color represents a single color in a color map.
|
||||||
|
type Color struct {
|
||||||
|
pf *PixelFormat
|
||||||
|
cm *ColorMap
|
||||||
|
cmIndex uint32 // Only valid if pf.TrueColor is false.
|
||||||
|
R, G, B uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type ColorMap [256]Color
|
||||||
|
|
||||||
|
type Conn interface {
|
||||||
|
io.ReadWriteCloser
|
||||||
|
Conn() net.Conn
|
||||||
|
Protocol() string
|
||||||
|
PixelFormat() *PixelFormat
|
||||||
|
SetPixelFormat(*PixelFormat) error
|
||||||
|
ColorMap() *ColorMap
|
||||||
|
SetColorMap(*ColorMap)
|
||||||
|
Encodings() []Encoding
|
||||||
|
SetEncodings([]EncodingType) error
|
||||||
|
Width() uint16
|
||||||
|
Height() uint16
|
||||||
|
SetWidth(uint16)
|
||||||
|
SetHeight(uint16)
|
||||||
|
DesktopName() string
|
||||||
|
SetDesktopName(string)
|
||||||
|
Flush() error
|
||||||
|
SetProtoVersion(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientMessage is the interface
|
||||||
|
type ClientMessage interface {
|
||||||
|
Type() ClientMessageType
|
||||||
|
Read(Conn) (ClientMessage, error)
|
||||||
|
Write(Conn) error
|
||||||
|
}
|
@ -1,5 +1,11 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
// An Encoding implements a method for encoding pixel data that is
|
// An Encoding implements a method for encoding pixel data that is
|
||||||
// sent by the server to the client.
|
// sent by the server to the client.
|
||||||
type Encoding interface {
|
type Encoding interface {
|
||||||
@ -22,3 +28,168 @@ const (
|
|||||||
EncodingTight = 7
|
EncodingTight = 7
|
||||||
EncodingZRLE = 16
|
EncodingZRLE = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EncodingType represents a known VNC encoding type.
|
||||||
|
type EncodingType int32
|
||||||
|
|
||||||
|
//go:generate stringer -type=EncodingType
|
||||||
|
|
||||||
|
const (
|
||||||
|
EncRaw EncodingType = 0
|
||||||
|
EncCopyRect EncodingType = 1
|
||||||
|
EncRRE EncodingType = 2
|
||||||
|
EncCoRRE EncodingType = 4
|
||||||
|
EncHextile EncodingType = 5
|
||||||
|
EncZlib EncodingType = 6
|
||||||
|
EncTight EncodingType = 7
|
||||||
|
EncZlibHex EncodingType = 8
|
||||||
|
EncUltra1 EncodingType = 9
|
||||||
|
EncUltra2 EncodingType = 10
|
||||||
|
EncJPEG EncodingType = 21
|
||||||
|
EncJRLE EncodingType = 22
|
||||||
|
EncTRLE EncodingType = 15
|
||||||
|
EncZRLE EncodingType = 16
|
||||||
|
EncJPEGQualityLevelPseudo10 EncodingType = -23
|
||||||
|
EncJPEGQualityLevelPseudo9 EncodingType = -24
|
||||||
|
EncJPEGQualityLevelPseudo8 EncodingType = -25
|
||||||
|
EncJPEGQualityLevelPseudo7 EncodingType = -26
|
||||||
|
EncJPEGQualityLevelPseudo6 EncodingType = -27
|
||||||
|
EncJPEGQualityLevelPseudo5 EncodingType = -28
|
||||||
|
EncJPEGQualityLevelPseudo4 EncodingType = -29
|
||||||
|
EncJPEGQualityLevelPseudo3 EncodingType = -30
|
||||||
|
EncJPEGQualityLevelPseudo2 EncodingType = -31
|
||||||
|
EncJPEGQualityLevelPseudo1 EncodingType = -32
|
||||||
|
EncColorPseudo EncodingType = -239
|
||||||
|
EncDesktopSizePseudo EncodingType = -223
|
||||||
|
EncLastRectPseudo EncodingType = -224
|
||||||
|
EncCompressionLevel10 EncodingType = -247
|
||||||
|
EncCompressionLevel9 EncodingType = -248
|
||||||
|
EncCompressionLevel8 EncodingType = -249
|
||||||
|
EncCompressionLevel7 EncodingType = -250
|
||||||
|
EncCompressionLevel6 EncodingType = -251
|
||||||
|
EncCompressionLevel5 EncodingType = -252
|
||||||
|
EncCompressionLevel4 EncodingType = -253
|
||||||
|
EncCompressionLevel3 EncodingType = -254
|
||||||
|
EncCompressionLevel2 EncodingType = -255
|
||||||
|
EncCompressionLevel1 EncodingType = -256
|
||||||
|
EncQEMUPointerMotionChangePseudo EncodingType = -257
|
||||||
|
EncQEMUExtendedKeyEventPseudo EncodingType = -258
|
||||||
|
EncTightPng EncodingType = -260
|
||||||
|
EncExtendedDesktopSizePseudo EncodingType = -308
|
||||||
|
EncXvpPseudo EncodingType = -309
|
||||||
|
EncFencePseudo EncodingType = -312
|
||||||
|
EncContinuousUpdatesPseudo EncodingType = -313
|
||||||
|
EncClientRedirect EncodingType = -311
|
||||||
|
)
|
||||||
|
|
||||||
|
// PixelFormat describes the way a pixel is formatted for a VNC connection.
|
||||||
|
//
|
||||||
|
// See RFC 6143 Section 7.4 for information on each of the fields.
|
||||||
|
type PixelFormat struct {
|
||||||
|
BPP uint8
|
||||||
|
Depth uint8
|
||||||
|
BigEndian bool
|
||||||
|
TrueColor bool
|
||||||
|
RedMax uint16
|
||||||
|
GreenMax uint16
|
||||||
|
BlueMax uint16
|
||||||
|
RedShift uint8
|
||||||
|
GreenShift uint8
|
||||||
|
BlueShift uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (format *PixelFormat) WriteTo(w io.Writer) ( error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
// Byte 1
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.BPP); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte 2
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.Depth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var boolByte byte
|
||||||
|
if format.BigEndian {
|
||||||
|
boolByte = 1
|
||||||
|
} else {
|
||||||
|
boolByte = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte 3 (BigEndian)
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if format.TrueColor {
|
||||||
|
boolByte = 1
|
||||||
|
} else {
|
||||||
|
boolByte = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte 4 (TrueColor)
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have true color enabled then we have to fill in the rest of the
|
||||||
|
// structure with the color values.
|
||||||
|
if format.TrueColor {
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.RedMax); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.GreenMax); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.BlueMax); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.RedShift); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.GreenShift); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, format.BlueShift); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(buf.Bytes()[0:16])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPixelFormat(bpp uint8) *PixelFormat {
|
||||||
|
bigEndian := false
|
||||||
|
// rgbMax := uint16(math.Exp2(float64(bpp))) - 1
|
||||||
|
rMax := uint16(255)
|
||||||
|
gMax := uint16(255)
|
||||||
|
bMax := uint16(255)
|
||||||
|
var (
|
||||||
|
tc = true
|
||||||
|
rs, gs, bs uint8
|
||||||
|
depth uint8
|
||||||
|
)
|
||||||
|
switch bpp {
|
||||||
|
case 8:
|
||||||
|
tc = false
|
||||||
|
depth = 8
|
||||||
|
rs, gs, bs = 0, 0, 0
|
||||||
|
case 16:
|
||||||
|
depth = 16
|
||||||
|
rs, gs, bs = 0, 4, 8
|
||||||
|
case 32:
|
||||||
|
depth = 24
|
||||||
|
// rs, gs, bs = 0, 8, 16
|
||||||
|
rs, gs, bs = 16, 8, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PixelFormat{bpp, depth, bigEndian, tc, rMax, gMax, bMax, rs, gs, bs}
|
||||||
|
}
|
||||||
|
@ -43,8 +43,8 @@ func (r *RfbReadHelper) SendRectSeparator(upcomingRectType int) error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RfbReadHelper) SendMessageSeparator(upcomingMessageType int) error {
|
func (r *RfbReadHelper) SendMessageSeparator(upcomingMessageType ServerMessageType) error {
|
||||||
seg := &RfbSegment{SegmentType: SegmentMessageSeparator, UpcomingObjectType: upcomingMessageType}
|
seg := &RfbSegment{SegmentType: SegmentMessageSeparator, UpcomingObjectType: int(upcomingMessageType)}
|
||||||
if r.Listener == nil {
|
if r.Listener == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,15 @@ func (r *Rectangle) String() string {
|
|||||||
// PixelFormat describes the way a pixel is formatted for a VNC connection.
|
// PixelFormat describes the way a pixel is formatted for a VNC connection.
|
||||||
//
|
//
|
||||||
// See RFC 6143 Section 7.4 for information on each of the fields.
|
// See RFC 6143 Section 7.4 for information on each of the fields.
|
||||||
type PixelFormat struct {
|
// type PixelFormat struct {
|
||||||
BPP uint8
|
// BPP uint8
|
||||||
Depth uint8
|
// Depth uint8
|
||||||
BigEndian bool
|
// BigEndian bool
|
||||||
TrueColor bool
|
// TrueColor bool
|
||||||
RedMax uint16
|
// RedMax uint16
|
||||||
GreenMax uint16
|
// GreenMax uint16
|
||||||
BlueMax uint16
|
// BlueMax uint16
|
||||||
RedShift uint8
|
// RedShift uint8
|
||||||
GreenShift uint8
|
// GreenShift uint8
|
||||||
BlueShift uint8
|
// BlueShift uint8
|
||||||
}
|
// }
|
||||||
|
25
common/server-message.go
Normal file
25
common/server-message.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
type IClientConn interface {
|
||||||
|
CurrentPixelFormat() *PixelFormat
|
||||||
|
CurrentColorMap() *ColorMap
|
||||||
|
Encodings() []Encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerMessage interface {
|
||||||
|
// The type of the message that is sent down on the wire.
|
||||||
|
Type() uint8
|
||||||
|
String() string
|
||||||
|
// Read reads the contents of the message from the reader. At the point
|
||||||
|
// this is called, the message type has already been read from the reader.
|
||||||
|
// This should return a new ServerMessage that is the appropriate type.
|
||||||
|
Read(IClientConn, *RfbReadHelper) (ServerMessage, error)
|
||||||
|
}
|
||||||
|
type ServerMessageType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
FramebufferUpdate ServerMessageType = iota
|
||||||
|
SetColourMapEntries
|
||||||
|
Bell
|
||||||
|
ServerCutText
|
||||||
|
)
|
@ -17,8 +17,8 @@ func (z *RREEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle,
|
|||||||
//read whole rect background color
|
//read whole rect background color
|
||||||
r.ReadBytes(bytesPerPixel)
|
r.ReadBytes(bytesPerPixel)
|
||||||
|
|
||||||
//read all individual rects (color=BPP + x=16b + y=16b + w=16b + h=16b)
|
//read all individual rects (color=bytesPerPixel + x=16b + y=16b + w=16b + h=16b)
|
||||||
_, err := r.ReadBytes(int(numOfSubrectangles) * (bytesPerPixel + 8))
|
_, err := r.ReadBytes(int(numOfSubrectangles) * (bytesPerPixel + 8)) // x+y+w+h=8 bytes
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -3,7 +3,6 @@ package encodings
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"vncproxy/common"
|
"vncproxy/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,13 +19,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TightEncoding struct {
|
type TightEncoding struct {
|
||||||
output io.Writer
|
//output io.Writer
|
||||||
logger common.Logger
|
logger common.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TightEncoding) SetOutput(output io.Writer) {
|
// func (t *TightEncoding) SetOutput(output io.Writer) {
|
||||||
t.output = output
|
// t.output = output
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (*TightEncoding) Type() int32 {
|
func (*TightEncoding) Type() int32 {
|
||||||
return 7
|
return 7
|
||||||
@ -100,6 +99,8 @@ func (t *TightEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangl
|
|||||||
fmt.Printf("reading fill size=%d\n", bytesPixel)
|
fmt.Printf("reading fill size=%d\n", bytesPixel)
|
||||||
//read color
|
//read color
|
||||||
r.ReadBytes(int(bytesPixel))
|
r.ReadBytes(int(bytesPixel))
|
||||||
|
//byt, _ := r.ReadBytes(3)
|
||||||
|
//fmt.Printf(">>>>>>>>>TightFillBytes=%v", byt)
|
||||||
return t, nil
|
return t, nil
|
||||||
case TightJpeg:
|
case TightJpeg:
|
||||||
if pixelFmt.BPP == 8 {
|
if pixelFmt.BPP == 8 {
|
||||||
|
@ -1,12 +1,25 @@
|
|||||||
package listeners
|
package listeners
|
||||||
|
|
||||||
import "vncproxy/common"
|
import (
|
||||||
import "io"
|
"errors"
|
||||||
|
"io"
|
||||||
|
"vncproxy/common"
|
||||||
|
)
|
||||||
|
|
||||||
type PassListener struct {
|
type PassListener struct {
|
||||||
io.Writer
|
io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*PassListener) Consume(seg *common.RfbSegment) error {
|
func (p *PassListener) Consume(seg *common.RfbSegment) error {
|
||||||
|
switch seg.SegmentType {
|
||||||
|
case common.SegmentMessageSeparator:
|
||||||
|
case common.SegmentRectSeparator:
|
||||||
|
case common.SegmentBytes:
|
||||||
|
_, err := p.Writer.Write(seg.Bytes)
|
||||||
|
return err
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New("undefined RfbSegment type")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,6 @@ func NewRecorder(saveFilePath string, desktopName string, fbWidth uint16, fbHeig
|
|||||||
return &rec
|
return &rec
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
FramebufferUpdate = 0
|
|
||||||
SetColourMapEntries = 1
|
|
||||||
Bell = 2
|
|
||||||
ServerCutText = 3
|
|
||||||
)
|
|
||||||
const versionMsg_3_3 = "RFB 003.003\n"
|
const versionMsg_3_3 = "RFB 003.003\n"
|
||||||
const versionMsg_3_7 = "RFB 003.007\n"
|
const versionMsg_3_7 = "RFB 003.007\n"
|
||||||
const versionMsg_3_8 = "RFB 003.008\n"
|
const versionMsg_3_8 = "RFB 003.008\n"
|
||||||
@ -96,12 +90,12 @@ func (r *Recorder) writeStartSession(desktopName string, framebufferWidth uint16
|
|||||||
func (r *Recorder) Consume(data *common.RfbSegment) error {
|
func (r *Recorder) Consume(data *common.RfbSegment) error {
|
||||||
switch data.SegmentType {
|
switch data.SegmentType {
|
||||||
case common.SegmentMessageSeparator:
|
case common.SegmentMessageSeparator:
|
||||||
switch data.UpcomingObjectType {
|
switch common.ServerMessageType(data.UpcomingObjectType) {
|
||||||
case FramebufferUpdate:
|
case common.FramebufferUpdate:
|
||||||
r.writeToDisk()
|
r.writeToDisk()
|
||||||
case SetColourMapEntries:
|
case common.SetColourMapEntries:
|
||||||
case Bell:
|
case common.Bell:
|
||||||
case ServerCutText:
|
case common.ServerCutText:
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown message type:" + string(data.UpcomingObjectType))
|
return errors.New("unknown message type:" + string(data.UpcomingObjectType))
|
||||||
}
|
}
|
||||||
|
19
main.go
19
main.go
@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
"vncproxy/common"
|
"vncproxy/common"
|
||||||
"vncproxy/encodings"
|
"vncproxy/encodings"
|
||||||
@ -21,8 +20,14 @@ func main() {
|
|||||||
var noauth vnc.ClientAuthNone
|
var noauth vnc.ClientAuthNone
|
||||||
authArr := []vnc.ClientAuth{&vnc.PasswordAuth{Password: "Ch_#!T@8"}, &noauth}
|
authArr := []vnc.ClientAuth{&vnc.PasswordAuth{Password: "Ch_#!T@8"}, &noauth}
|
||||||
|
|
||||||
vncSrvMessagesChan := make(chan vnc.ServerMessage)
|
vncSrvMessagesChan := make(chan common.ServerMessage)
|
||||||
clientConn, err := vnc.Client(nc, &vnc.ClientConfig{Auth: authArr, ServerMessageCh: vncSrvMessagesChan, Exclusive: true})
|
clientConn, err := vnc.Client(nc,
|
||||||
|
&vnc.ClientConfig{
|
||||||
|
Auth: authArr,
|
||||||
|
ServerMessageCh: vncSrvMessagesChan,
|
||||||
|
Exclusive: true,
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error creating client: %s", err)
|
fmt.Printf("error creating client: %s", err)
|
||||||
}
|
}
|
||||||
@ -38,10 +43,10 @@ func main() {
|
|||||||
cpyRect := encodings.CopyRectEncoding{}
|
cpyRect := encodings.CopyRectEncoding{}
|
||||||
//coRRE := encodings.CoRREEncoding{}
|
//coRRE := encodings.CoRREEncoding{}
|
||||||
//hextile := encodings.HextileEncoding{}
|
//hextile := encodings.HextileEncoding{}
|
||||||
file, _ := os.OpenFile("stam.bin", os.O_CREATE|os.O_RDWR, 0755)
|
// file, _ := os.OpenFile("stam.bin", os.O_CREATE|os.O_RDWR, 0755)
|
||||||
defer file.Close()
|
// defer file.Close()
|
||||||
|
|
||||||
tight.SetOutput(file)
|
//tight.SetOutput(file)
|
||||||
clientConn.SetEncodings([]common.Encoding{&cpyRect, &tight})
|
clientConn.SetEncodings([]common.Encoding{&cpyRect, &tight})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -50,7 +55,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error requesting fb update: %s\n", err)
|
fmt.Printf("error requesting fb update: %s\n", err)
|
||||||
}
|
}
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
247
server/client-messages.go
Normal file
247
server/client-messages.go
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"vncproxy/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetPixelFormat holds the wire format message.
|
||||||
|
type SetPixelFormat struct {
|
||||||
|
_ [3]byte // padding
|
||||||
|
PF common.PixelFormat // pixel-format
|
||||||
|
_ [3]byte // padding after pixel format
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key represents a VNC key press.
|
||||||
|
type Key uint32
|
||||||
|
|
||||||
|
//go:generate stringer -type=Key
|
||||||
|
|
||||||
|
// Keys is a slice of Key values.
|
||||||
|
type Keys []Key
|
||||||
|
|
||||||
|
func (*SetPixelFormat) Type() common.ClientMessageType {
|
||||||
|
return common.SetPixelFormatMsgType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *SetPixelFormat) Write(c common.Conn) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
pf := c.PixelFormat()
|
||||||
|
// Invalidate the color map.
|
||||||
|
if pf.TrueColor {
|
||||||
|
c.SetColorMap(&common.ColorMap{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SetPixelFormat) Read(c common.Conn) (common.ClientMessage, error) {
|
||||||
|
msg := SetPixelFormat{}
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEncodings holds the wire format message, sans encoding-type field.
|
||||||
|
type SetEncodings struct {
|
||||||
|
_ [1]byte // padding
|
||||||
|
EncNum uint16 // number-of-encodings
|
||||||
|
Encodings []common.EncodingType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SetEncodings) Type() common.ClientMessageType {
|
||||||
|
return common.SetEncodingsMsgType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SetEncodings) Read(c common.Conn) (common.ClientMessage, error) {
|
||||||
|
msg := SetEncodings{}
|
||||||
|
var pad [1]byte
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg.EncNum); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var enc common.EncodingType
|
||||||
|
for i := uint16(0); i < msg.EncNum; i++ {
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &enc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msg.Encodings = append(msg.Encodings, enc)
|
||||||
|
}
|
||||||
|
c.SetEncodings(msg.Encodings)
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *SetEncodings) Write(c common.Conn) error {
|
||||||
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pad [1]byte
|
||||||
|
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint16(len(msg.Encodings)) > msg.EncNum {
|
||||||
|
msg.EncNum = uint16(len(msg.Encodings))
|
||||||
|
}
|
||||||
|
if err := binary.Write(c, binary.BigEndian, msg.EncNum); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, enc := range msg.Encodings {
|
||||||
|
if err := binary.Write(c, binary.BigEndian, enc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FramebufferUpdateRequest holds the wire format message.
|
||||||
|
type FramebufferUpdateRequest struct {
|
||||||
|
Inc uint8 // incremental
|
||||||
|
X, Y uint16 // x-, y-position
|
||||||
|
Width, Height uint16 // width, height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*FramebufferUpdateRequest) Type() common.ClientMessageType {
|
||||||
|
return common.FramebufferUpdateRequestMsgType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*FramebufferUpdateRequest) Read(c common.Conn) (common.ClientMessage, error) {
|
||||||
|
msg := FramebufferUpdateRequest{}
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *FramebufferUpdateRequest) Write(c common.Conn) 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 c.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyEvent holds the wire format message.
|
||||||
|
type KeyEvent struct {
|
||||||
|
Down uint8 // down-flag
|
||||||
|
_ [2]byte // padding
|
||||||
|
Key Key // key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*KeyEvent) Type() common.ClientMessageType {
|
||||||
|
return common.KeyEventMsgType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*KeyEvent) Read(c common.Conn) (common.ClientMessage, error) {
|
||||||
|
msg := KeyEvent{}
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *KeyEvent) Write(c common.Conn) 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 c.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PointerEventMessage holds the wire format message.
|
||||||
|
type PointerEvent struct {
|
||||||
|
Mask uint8 // button-mask
|
||||||
|
X, Y uint16 // x-, y-position
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PointerEvent) Type() common.ClientMessageType {
|
||||||
|
return common.PointerEventMsgType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PointerEvent) Read(c common.Conn) (common.ClientMessage, error) {
|
||||||
|
msg := PointerEvent{}
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *PointerEvent) Write(c common.Conn) 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 c.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientCutText holds the wire format message, sans the text field.
|
||||||
|
type ClientCutText struct {
|
||||||
|
_ [3]byte // padding
|
||||||
|
Length uint32 // length
|
||||||
|
Text []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ClientCutText) Type() common.ClientMessageType {
|
||||||
|
return common.ClientCutTextMsgType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ClientCutText) Read(c common.Conn) (common.ClientMessage, error) {
|
||||||
|
msg := ClientCutText{}
|
||||||
|
var pad [3]byte
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg.Length); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Text = make([]byte, msg.Length)
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &msg.Text); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *ClientCutText) Write(c common.Conn) error {
|
||||||
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pad [3]byte
|
||||||
|
if err := binary.Write(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint32(len(msg.Text)) > msg.Length {
|
||||||
|
msg.Length = uint32(len(msg.Text))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(c, binary.BigEndian, msg.Length); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(c, binary.BigEndian, msg.Text); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Flush()
|
||||||
|
}
|
BIN
server/debug.test
Normal file
BIN
server/debug.test
Normal file
Binary file not shown.
492
server/handlers.go
Normal file
492
server/handlers.go
Normal file
@ -0,0 +1,492 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// // ClientMessage is the interface
|
||||||
|
// type ClientMessage interface {
|
||||||
|
// Type() ClientMessageType
|
||||||
|
// Read(Conn) (ClientMessage, error)
|
||||||
|
// Write(Conn) error
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ServerMessage is the interface
|
||||||
|
// type ServerMessage interface {
|
||||||
|
// Type() ServerMessageType
|
||||||
|
// Read(Conn) (ServerMessage, error)
|
||||||
|
// Write(Conn) error
|
||||||
|
// }
|
||||||
|
|
||||||
|
const ProtoVersionLength = 12
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProtoVersionUnknown = ""
|
||||||
|
ProtoVersion33 = "RFB 003.003\n"
|
||||||
|
ProtoVersion38 = "RFB 003.008\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseProtoVersion(pv []byte) (uint, uint, error) {
|
||||||
|
var major, minor uint
|
||||||
|
|
||||||
|
if len(pv) < ProtoVersionLength {
|
||||||
|
return 0, 0, fmt.Errorf("ProtocolVersion message too short (%v < %v)", len(pv), ProtoVersionLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := fmt.Sscanf(string(pv), "RFB %d.%d\n", &major, &minor)
|
||||||
|
if l != 2 {
|
||||||
|
return 0, 0, fmt.Errorf("error parsing ProtocolVersion.")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return major, minor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// func ClientVersionHandler(cfg *ClientConfig, c ServerConn) error {
|
||||||
|
// var version [ProtoVersionLength]byte
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &version); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// major, minor, err := ParseProtoVersion(version[:])
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pv := ProtoVersionUnknown
|
||||||
|
// if major == 3 {
|
||||||
|
// if minor >= 8 {
|
||||||
|
// pv = ProtoVersion38
|
||||||
|
// } else if minor >= 3 {
|
||||||
|
// pv = ProtoVersion38
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if pv == ProtoVersionUnknown {
|
||||||
|
// return fmt.Errorf("ProtocolVersion handshake failed; unsupported version '%v'", string(version[:]))
|
||||||
|
// }
|
||||||
|
// c.SetProtoVersion(string(version[:]))
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, []byte(pv)); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return c.Flush()
|
||||||
|
// }
|
||||||
|
|
||||||
|
func ServerVersionHandler(cfg *ServerConfig, c *ServerConn) error {
|
||||||
|
var version [ProtoVersionLength]byte
|
||||||
|
if err := binary.Write(c, binary.BigEndian, []byte(ProtoVersion38)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
major, minor, err := ParseProtoVersion(version[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pv := ProtoVersionUnknown
|
||||||
|
if major == 3 {
|
||||||
|
if minor >= 8 {
|
||||||
|
pv = ProtoVersion38
|
||||||
|
} else if minor >= 3 {
|
||||||
|
pv = ProtoVersion33
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pv == ProtoVersionUnknown {
|
||||||
|
return fmt.Errorf("ProtocolVersion handshake failed; unsupported version '%v'", string(version[:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetProtoVersion(pv)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// func ClientSecurityHandler(cfg *ClientConfig, c Conn) error {
|
||||||
|
// var numSecurityTypes uint8
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &numSecurityTypes); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// secTypes := make([]SecurityType, numSecurityTypes)
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &secTypes); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var secType SecurityHandler
|
||||||
|
// for _, st := range cfg.SecurityHandlers {
|
||||||
|
// for _, sc := range secTypes {
|
||||||
|
// if st.Type() == sc {
|
||||||
|
// secType = st
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, cfg.SecurityHandlers[0].Type()); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := c.Flush(); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err := secType.Auth(c)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var authCode uint32
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &authCode); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if authCode == 1 {
|
||||||
|
// var reasonLength uint32
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &reasonLength); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// reasonText := make([]byte, reasonLength)
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &reasonText); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return fmt.Errorf("%s", reasonText)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
func ServerSecurityHandler(cfg *ServerConfig, c *ServerConn) error {
|
||||||
|
if err := binary.Write(c, binary.BigEndian, uint8(len(cfg.SecurityHandlers))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sectype := range cfg.SecurityHandlers {
|
||||||
|
if err := binary.Write(c, binary.BigEndian, sectype.Type()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var secType SecurityType
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
secTypes := make(map[SecurityType]SecurityHandler)
|
||||||
|
for _, sType := range cfg.SecurityHandlers {
|
||||||
|
secTypes[sType.Type()] = sType
|
||||||
|
}
|
||||||
|
|
||||||
|
sType, ok := secTypes[secType]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("server type %d not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
var authCode uint32
|
||||||
|
authErr := sType.Auth(c)
|
||||||
|
if authErr != nil {
|
||||||
|
authCode = uint32(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(c, binary.BigEndian, authCode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if authErr != nil {
|
||||||
|
if err := binary.Write(c, binary.BigEndian, len(authErr.Error())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(c, binary.BigEndian, []byte(authErr.Error())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return authErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// func ClientServerInitHandler(cfg *ClientConfig, c *ServerConn) error {
|
||||||
|
// srvInit := &ServerInit{}
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &srvInit.FBWidth); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &srvInit.FBHeight); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &srvInit.PixelFormat); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &srvInit.NameLength); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// nameText := make([]byte, srvInit.NameLength)
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, nameText); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// srvInit.NameText = nameText
|
||||||
|
// c.SetDesktopName(string(srvInit.NameText))
|
||||||
|
// c.SetWidth(srvInit.FBWidth)
|
||||||
|
// c.SetHeight(srvInit.FBHeight)
|
||||||
|
// c.SetPixelFormat(&srvInit.PixelFormat)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
func ServerServerInitHandler(cfg *ServerConfig, c *ServerConn) error {
|
||||||
|
srvInit := &ServerInit{
|
||||||
|
FBWidth: c.Width(),
|
||||||
|
FBHeight: c.Height(),
|
||||||
|
PixelFormat: *c.PixelFormat(),
|
||||||
|
NameLength: uint32(len(cfg.DesktopName)),
|
||||||
|
NameText: []byte(cfg.DesktopName),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(c, binary.BigEndian, srvInit.FBWidth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(c, binary.BigEndian, srvInit.FBHeight); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := srvInit.PixelFormat.WriteTo(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(c, binary.BigEndian, srvInit.NameLength); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(c, binary.BigEndian, srvInit.NameText); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//serverCaps:=[]TightCapability{
|
||||||
|
// TightCapability{uint32(1), [4]byte(StandardVendor), [8]byte("12345678")},
|
||||||
|
//}
|
||||||
|
//clientCaps:=[]TightCapability{
|
||||||
|
// TightCapability{uint32(1), [4]byte(StandardVendor), [8]byte("12345678")},
|
||||||
|
//}
|
||||||
|
//encodingCaps:=[]TightCapability{
|
||||||
|
// TightCapability{uint32(1), [4]byte(StandardVendor), [8]byte("12345678")},
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//tightInit:=TightServerInit{
|
||||||
|
// serverCaps,clientCaps,encodingCaps,
|
||||||
|
//}
|
||||||
|
//tightInit.WriteTo(c)
|
||||||
|
|
||||||
|
return c.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
StandardVendor = "STDV"
|
||||||
|
TridiaVncVendor = "TRDV"
|
||||||
|
TightVncVendor = "TGHT"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
void initCapabilities() {
|
||||||
|
tunnelCaps = new CapsContainer();
|
||||||
|
authCaps = new CapsContainer();
|
||||||
|
serverMsgCaps = new CapsContainer();
|
||||||
|
clientMsgCaps = new CapsContainer();
|
||||||
|
encodingCaps = new CapsContainer();
|
||||||
|
|
||||||
|
// Supported authentication methods
|
||||||
|
authCaps.add(AuthNone, StandardVendor, SigAuthNone,
|
||||||
|
"No authentication");
|
||||||
|
authCaps.add(AuthVNC, StandardVendor, SigAuthVNC,
|
||||||
|
"Standard VNC password authentication");
|
||||||
|
|
||||||
|
// Supported non-standard server-to-client messages
|
||||||
|
// [NONE]
|
||||||
|
|
||||||
|
// Supported non-standard client-to-server messages
|
||||||
|
// [NONE]
|
||||||
|
|
||||||
|
// Supported encoding types
|
||||||
|
encodingCaps.add(EncodingCopyRect, StandardVendor,
|
||||||
|
SigEncodingCopyRect, "Standard CopyRect encoding");
|
||||||
|
encodingCaps.add(EncodingRRE, StandardVendor,
|
||||||
|
SigEncodingRRE, "Standard RRE encoding");
|
||||||
|
encodingCaps.add(EncodingCoRRE, StandardVendor,
|
||||||
|
SigEncodingCoRRE, "Standard CoRRE encoding");
|
||||||
|
encodingCaps.add(EncodingHextile, StandardVendor,
|
||||||
|
SigEncodingHextile, "Standard Hextile encoding");
|
||||||
|
encodingCaps.add(EncodingZRLE, StandardVendor,
|
||||||
|
SigEncodingZRLE, "Standard ZRLE encoding");
|
||||||
|
encodingCaps.add(EncodingZlib, TridiaVncVendor,
|
||||||
|
SigEncodingZlib, "Zlib encoding");
|
||||||
|
encodingCaps.add(EncodingTight, TightVncVendor,
|
||||||
|
SigEncodingTight, "Tight encoding");
|
||||||
|
|
||||||
|
// Supported pseudo-encoding types
|
||||||
|
encodingCaps.add(EncodingCompressLevel0, TightVncVendor,
|
||||||
|
SigEncodingCompressLevel0, "Compression level");
|
||||||
|
encodingCaps.add(EncodingQualityLevel0, TightVncVendor,
|
||||||
|
SigEncodingQualityLevel0, "JPEG quality level");
|
||||||
|
encodingCaps.add(EncodingXCursor, TightVncVendor,
|
||||||
|
SigEncodingXCursor, "X-style cursor shape update");
|
||||||
|
encodingCaps.add(EncodingRichCursor, TightVncVendor,
|
||||||
|
SigEncodingRichCursor, "Rich-color cursor shape update");
|
||||||
|
encodingCaps.add(EncodingPointerPos, TightVncVendor,
|
||||||
|
SigEncodingPointerPos, "Pointer position update");
|
||||||
|
encodingCaps.add(EncodingLastRect, TightVncVendor,
|
||||||
|
SigEncodingLastRect, "LastRect protocol extension");
|
||||||
|
encodingCaps.add(EncodingNewFBSize, TightVncVendor,
|
||||||
|
SigEncodingNewFBSize, "Framebuffer size change");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
type TightServerInit struct {
|
||||||
|
ServerMessageCaps []TightCapability
|
||||||
|
ClientMessageCaps []TightCapability
|
||||||
|
EncodingCaps []TightCapability
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TightServerInit) ReadFrom(r io.Reader) error {
|
||||||
|
var numSrvCaps uint16
|
||||||
|
var numCliCaps uint16
|
||||||
|
var numEncCaps uint16
|
||||||
|
var padding uint16
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &numSrvCaps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &numCliCaps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &numEncCaps); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &padding); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(numSrvCaps); i++ {
|
||||||
|
cap := TightCapability{}
|
||||||
|
cap.ReadFrom(r)
|
||||||
|
t.ServerMessageCaps = append(t.ServerMessageCaps, cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(numCliCaps); i++ {
|
||||||
|
cap := TightCapability{}
|
||||||
|
cap.ReadFrom(r)
|
||||||
|
t.ClientMessageCaps = append(t.ClientMessageCaps, cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(numEncCaps); i++ {
|
||||||
|
cap := TightCapability{}
|
||||||
|
cap.ReadFrom(r)
|
||||||
|
t.EncodingCaps = append(t.EncodingCaps, cap)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TightServerInit) WriteTo(w io.Writer) error {
|
||||||
|
if err := binary.Write(w, binary.BigEndian, uint16(len(t.ServerMessageCaps))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(w, binary.BigEndian, uint16(len(t.ClientMessageCaps))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(w, binary.BigEndian, uint16(len(t.EncodingCaps))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(w, binary.BigEndian, uint16(0)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range t.ServerMessageCaps {
|
||||||
|
s.WriteTo(w)
|
||||||
|
}
|
||||||
|
for _, s := range t.ClientMessageCaps {
|
||||||
|
s.WriteTo(w)
|
||||||
|
}
|
||||||
|
for _, s := range t.EncodingCaps {
|
||||||
|
s.WriteTo(w)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TightCapability struct {
|
||||||
|
code uint32
|
||||||
|
vendor [4]byte
|
||||||
|
name [8]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TightCapability) WriteTo(w io.Writer) error {
|
||||||
|
if err := binary.Write(w, binary.BigEndian, t.code); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(w, binary.BigEndian, t.vendor); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(w, binary.BigEndian, t.name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TightCapability) ReadFrom(r io.Reader) error {
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &t.code); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &t.vendor); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &t.name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// func ClientClientInitHandler(cfg *ClientConfig, c *ServerConn) error {
|
||||||
|
// var shared uint8
|
||||||
|
// if cfg.Exclusive {
|
||||||
|
// shared = 0
|
||||||
|
// } else {
|
||||||
|
// shared = 1
|
||||||
|
// }
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, shared); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return c.Flush()
|
||||||
|
// }
|
||||||
|
|
||||||
|
func ServerClientInitHandler(cfg *ServerConfig, c *ServerConn) error {
|
||||||
|
var shared uint8
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &shared); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/* TODO
|
||||||
|
if shared != 1 {
|
||||||
|
c.SetShared(false)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
333
server/security.go
Normal file
333
server/security.go
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"vncproxy/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecurityType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecTypeUnknown = SecurityType(0)
|
||||||
|
SecTypeNone = SecurityType(1)
|
||||||
|
SecTypeVNC = SecurityType(2)
|
||||||
|
SecTypeVeNCrypt = SecurityType(19)
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecuritySubType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecSubTypeUnknown = SecuritySubType(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecSubTypeVeNCrypt01Unknown = SecuritySubType(0)
|
||||||
|
SecSubTypeVeNCrypt01Plain = SecuritySubType(19)
|
||||||
|
SecSubTypeVeNCrypt01TLSNone = SecuritySubType(20)
|
||||||
|
SecSubTypeVeNCrypt01TLSVNC = SecuritySubType(21)
|
||||||
|
SecSubTypeVeNCrypt01TLSPlain = SecuritySubType(22)
|
||||||
|
SecSubTypeVeNCrypt01X509None = SecuritySubType(23)
|
||||||
|
SecSubTypeVeNCrypt01X509VNC = SecuritySubType(24)
|
||||||
|
SecSubTypeVeNCrypt01X509Plain = SecuritySubType(25)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecSubTypeVeNCrypt02Unknown = SecuritySubType(0)
|
||||||
|
SecSubTypeVeNCrypt02Plain = SecuritySubType(256)
|
||||||
|
SecSubTypeVeNCrypt02TLSNone = SecuritySubType(257)
|
||||||
|
SecSubTypeVeNCrypt02TLSVNC = SecuritySubType(258)
|
||||||
|
SecSubTypeVeNCrypt02TLSPlain = SecuritySubType(259)
|
||||||
|
SecSubTypeVeNCrypt02X509None = SecuritySubType(260)
|
||||||
|
SecSubTypeVeNCrypt02X509VNC = SecuritySubType(261)
|
||||||
|
SecSubTypeVeNCrypt02X509Plain = SecuritySubType(262)
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecurityHandler interface {
|
||||||
|
Type() SecurityType
|
||||||
|
SubType() SecuritySubType
|
||||||
|
Auth(common.Conn) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// type ClientAuthNone struct{}
|
||||||
|
|
||||||
|
// func (*ClientAuthNone) Type() SecurityType {
|
||||||
|
// return SecTypeNone
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*ClientAuthNone) SubType() SecuritySubType {
|
||||||
|
// return SecSubTypeUnknown
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*ClientAuthNone) Auth(conn common.Conn) error {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ServerAuthNone is the "none" authentication. See 7.2.1.
|
||||||
|
type ServerAuthNone struct{}
|
||||||
|
|
||||||
|
func (*ServerAuthNone) Type() SecurityType {
|
||||||
|
return SecTypeNone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ServerAuthNone) Auth(c common.Conn) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ServerAuthNone) SubType() SecuritySubType {
|
||||||
|
return SecSubTypeUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (*ClientAuthVeNCrypt02Plain) Type() SecurityType {
|
||||||
|
// return SecTypeVeNCrypt
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*ClientAuthVeNCrypt02Plain) SubType() SecuritySubType {
|
||||||
|
// return SecSubTypeVeNCrypt02Plain
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ClientAuthVeNCryptPlain see https://www.berrange.com/~dan/vencrypt.txt
|
||||||
|
// type ClientAuthVeNCrypt02Plain struct {
|
||||||
|
// Username []byte
|
||||||
|
// Password []byte
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (auth *ClientAuthVeNCrypt02Plain) Auth(c common.Conn) error {
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, []uint8{0, 2}); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := c.Flush(); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// var (
|
||||||
|
// major, minor uint8
|
||||||
|
// )
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &major); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &minor); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// res := uint8(1)
|
||||||
|
// if major == 0 && minor == 2 {
|
||||||
|
// res = uint8(0)
|
||||||
|
// }
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, res); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// c.Flush()
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, uint8(1)); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, auth.SubType()); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := c.Flush(); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// var secType SecuritySubType
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if secType != auth.SubType() {
|
||||||
|
// binary.Write(c, binary.BigEndian, uint8(1))
|
||||||
|
// c.Flush()
|
||||||
|
// return fmt.Errorf("invalid sectype")
|
||||||
|
// }
|
||||||
|
// if len(auth.Password) == 0 || len(auth.Username) == 0 {
|
||||||
|
// return fmt.Errorf("Security Handshake failed; no username and/or password provided for VeNCryptAuth.")
|
||||||
|
// }
|
||||||
|
// /*
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Username))); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Password))); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, auth.Username); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, auth.Password); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// */
|
||||||
|
// var (
|
||||||
|
// uLength, pLength uint32
|
||||||
|
// )
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &uLength); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &pLength); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// username := make([]byte, uLength)
|
||||||
|
// password := make([]byte, pLength)
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &username); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &password); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if !bytes.Equal(auth.Username, username) || !bytes.Equal(auth.Password, password) {
|
||||||
|
// return fmt.Errorf("invalid username/password")
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ServerAuthVNC is the standard password authentication. See 7.2.2.
|
||||||
|
type ServerAuthVNC struct{}
|
||||||
|
|
||||||
|
func (*ServerAuthVNC) Type() SecurityType {
|
||||||
|
return SecTypeVNC
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ServerAuthVNC) SubType() SecuritySubType {
|
||||||
|
return SecSubTypeUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
const AUTH_FAIL = "Authentication Failure"
|
||||||
|
|
||||||
|
func (auth *ServerAuthVNC) Auth(c common.Conn) error {
|
||||||
|
buf := make([]byte, 8+len([]byte(AUTH_FAIL)))
|
||||||
|
rand.Read(buf[:16]) // Random 16 bytes in buf
|
||||||
|
sndsz, err := c.Write(buf[:16])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error sending challenge to client: %s\n", err.Error())
|
||||||
|
return errors.New("Error sending challenge to client:" + err.Error())
|
||||||
|
}
|
||||||
|
if sndsz != 16 {
|
||||||
|
log.Printf("The full 16 byte challenge was not sent!\n")
|
||||||
|
return errors.New("The full 16 byte challenge was not sent")
|
||||||
|
}
|
||||||
|
c.Flush()
|
||||||
|
buf2 := make([]byte, 16)
|
||||||
|
_, err = c.Read(buf2)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("The authentication result was not read: %s\n", err.Error())
|
||||||
|
return errors.New("The authentication result was not read" + err.Error())
|
||||||
|
}
|
||||||
|
AuthText := "1234"
|
||||||
|
bk, err := des.NewCipher([]byte(fixDesKey(AuthText)))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error generating authentication cipher: %s\n", err.Error())
|
||||||
|
return errors.New("Error generating authentication cipher")
|
||||||
|
}
|
||||||
|
buf3 := make([]byte, 16)
|
||||||
|
bk.Encrypt(buf3, buf) //Encrypt first 8 bytes
|
||||||
|
bk.Encrypt(buf3[8:], buf[8:]) // Encrypt second 8 bytes
|
||||||
|
if bytes.Compare(buf2, buf3) != 0 { // If the result does not decrypt correctly to what we sent then a problem
|
||||||
|
SetUint32(buf, 0, 1)
|
||||||
|
SetUint32(buf, 4, uint32(len([]byte(AUTH_FAIL))))
|
||||||
|
copy(buf[8:], []byte(AUTH_FAIL))
|
||||||
|
c.Write(buf)
|
||||||
|
c.Flush()
|
||||||
|
return errors.New("Authentication failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUint32 set 4 bytes at pos in buf to the val (in big endian format)
|
||||||
|
// A test is done to ensure there are 4 bytes available at pos in the buffer
|
||||||
|
func SetUint32(buf []byte, pos int, val uint32) {
|
||||||
|
if pos+4 > len(buf) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
buf[3-i+pos] = byte(val)
|
||||||
|
val >>= 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixDesKeyByte is used to mirror a byte's bits
|
||||||
|
// This is not clearly indicated by the document, but is in actual fact used
|
||||||
|
func fixDesKeyByte(val byte) byte {
|
||||||
|
var newval byte = 0
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
newval <<= 1
|
||||||
|
newval += (val & 1)
|
||||||
|
val >>= 1
|
||||||
|
}
|
||||||
|
return newval
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixDesKey will make sure that exactly 8 bytes is used either by truncating or padding with nulls
|
||||||
|
// The bytes are then bit mirrored and returned
|
||||||
|
func fixDesKey(key string) []byte {
|
||||||
|
tmp := []byte(key)
|
||||||
|
buf := make([]byte, 8)
|
||||||
|
if len(tmp) <= 8 {
|
||||||
|
copy(buf, tmp)
|
||||||
|
} else {
|
||||||
|
copy(buf, tmp[:8])
|
||||||
|
}
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
buf[i] = fixDesKeyByte(buf[i])
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// // ClientAuthVNC is the standard password authentication. See 7.2.2.
|
||||||
|
// type ClientAuthVNC struct {
|
||||||
|
// Challenge [16]byte
|
||||||
|
// Password []byte
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*ClientAuthVNC) Type() SecurityType {
|
||||||
|
// return SecTypeVNC
|
||||||
|
// }
|
||||||
|
// func (*ClientAuthVNC) SubType() SecuritySubType {
|
||||||
|
// return SecSubTypeUnknown
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (auth *ClientAuthVNC) Auth(c common.Conn) error {
|
||||||
|
// if len(auth.Password) == 0 {
|
||||||
|
// return fmt.Errorf("Security Handshake failed; no password provided for VNCAuth.")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, auth.Challenge); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// auth.encode()
|
||||||
|
|
||||||
|
// // Send the encrypted challenge back to server
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, auth.Challenge); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return c.Flush()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (auth *ClientAuthVNC) encode() error {
|
||||||
|
// // Copy password string to 8 byte 0-padded slice
|
||||||
|
// key := make([]byte, 8)
|
||||||
|
// copy(key, auth.Password)
|
||||||
|
|
||||||
|
// // Each byte of the password needs to be reversed. This is a
|
||||||
|
// // non RFC-documented behaviour of VNC clients and servers
|
||||||
|
// for i := range key {
|
||||||
|
// key[i] = (key[i]&0x55)<<1 | (key[i]&0xAA)>>1 // Swap adjacent bits
|
||||||
|
// key[i] = (key[i]&0x33)<<2 | (key[i]&0xCC)>>2 // Swap adjacent pairs
|
||||||
|
// key[i] = (key[i]&0x0F)<<4 | (key[i]&0xF0)>>4 // Swap the 2 halves
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Encrypt challenge with key.
|
||||||
|
// cipher, err := des.NewCipher(key)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// for i := 0; i < len(auth.Challenge); i += cipher.BlockSize() {
|
||||||
|
// cipher.Encrypt(auth.Challenge[i:i+cipher.BlockSize()], auth.Challenge[i:i+cipher.BlockSize()])
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }
|
137
server/server-conn.go
Normal file
137
server/server-conn.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"vncproxy/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerConn struct {
|
||||||
|
c net.Conn
|
||||||
|
cfg *ServerConfig
|
||||||
|
br *bufio.Reader
|
||||||
|
bw *bufio.Writer
|
||||||
|
protocol string
|
||||||
|
m sync.Mutex
|
||||||
|
// If the pixel format uses a color map, then this is the color
|
||||||
|
// map that is used. This should not be modified directly, since
|
||||||
|
// the data comes from the server.
|
||||||
|
// Definition in §5 - Representation of Pixel Data.
|
||||||
|
colorMap *common.ColorMap
|
||||||
|
|
||||||
|
// Name associated with the desktop, sent from the server.
|
||||||
|
desktopName string
|
||||||
|
|
||||||
|
// Encodings supported by the client. This should not be modified
|
||||||
|
// directly. Instead, SetEncodings() should be used.
|
||||||
|
encodings []common.Encoding
|
||||||
|
|
||||||
|
// Height of the frame buffer in pixels, sent to the client.
|
||||||
|
fbHeight uint16
|
||||||
|
|
||||||
|
// Width of the frame buffer in pixels, sent to the client.
|
||||||
|
fbWidth uint16
|
||||||
|
|
||||||
|
// The pixel format associated with the connection. This shouldn't
|
||||||
|
// be modified. If you wish to set a new pixel format, use the
|
||||||
|
// SetPixelFormat method.
|
||||||
|
pixelFormat *common.PixelFormat
|
||||||
|
|
||||||
|
quit chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) UnreadByte() error {
|
||||||
|
return c.br.UnreadByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) Conn() net.Conn {
|
||||||
|
return c.c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) SetEncodings(encs []common.EncodingType) error {
|
||||||
|
encodings := make(map[int32]common.Encoding)
|
||||||
|
for _, enc := range c.cfg.Encodings {
|
||||||
|
encodings[enc.Type()] = enc
|
||||||
|
}
|
||||||
|
for _, encType := range encs {
|
||||||
|
if enc, ok := encodings[int32(encType)]; ok {
|
||||||
|
c.encodings = append(c.encodings, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) SetProtoVersion(pv string) {
|
||||||
|
c.protocol = pv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) Flush() error {
|
||||||
|
// c.m.Lock()
|
||||||
|
// defer c.m.Unlock()
|
||||||
|
return c.bw.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) Close() error {
|
||||||
|
return c.c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (c *ServerConn) Input() chan *ServerMessage {
|
||||||
|
return c.cfg.ServerMessageCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) Output() chan *ClientMessage {
|
||||||
|
return c.cfg.ClientMessageCh
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
func (c *ServerConn) Read(buf []byte) (int, error) {
|
||||||
|
return c.br.Read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) Write(buf []byte) (int, error) {
|
||||||
|
// c.m.Lock()
|
||||||
|
// defer c.m.Unlock()
|
||||||
|
return c.bw.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) ColorMap() *common.ColorMap {
|
||||||
|
return c.colorMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) SetColorMap(cm *common.ColorMap) {
|
||||||
|
c.colorMap = cm
|
||||||
|
}
|
||||||
|
func (c *ServerConn) DesktopName() string {
|
||||||
|
return c.desktopName
|
||||||
|
}
|
||||||
|
func (c *ServerConn) PixelFormat() *common.PixelFormat {
|
||||||
|
return c.pixelFormat
|
||||||
|
}
|
||||||
|
func (c *ServerConn) SetDesktopName(name string) {
|
||||||
|
c.desktopName = name
|
||||||
|
}
|
||||||
|
func (c *ServerConn) SetPixelFormat(pf *common.PixelFormat) error {
|
||||||
|
c.pixelFormat = pf
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *ServerConn) Encodings() []common.Encoding {
|
||||||
|
return c.encodings
|
||||||
|
}
|
||||||
|
func (c *ServerConn) Width() uint16 {
|
||||||
|
return c.fbWidth
|
||||||
|
}
|
||||||
|
func (c *ServerConn) Height() uint16 {
|
||||||
|
return c.fbHeight
|
||||||
|
}
|
||||||
|
func (c *ServerConn) Protocol() string {
|
||||||
|
return c.protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO send desktopsize pseudo encoding
|
||||||
|
func (c *ServerConn) SetWidth(w uint16) {
|
||||||
|
c.fbWidth = w
|
||||||
|
}
|
||||||
|
func (c *ServerConn) SetHeight(h uint16) {
|
||||||
|
c.fbHeight = h
|
||||||
|
}
|
366
server/server.go
Normal file
366
server/server.go
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"vncproxy/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DefaultClientMessages = []common.ClientMessage{
|
||||||
|
&SetPixelFormat{},
|
||||||
|
&SetEncodings{},
|
||||||
|
&FramebufferUpdateRequest{},
|
||||||
|
&KeyEvent{},
|
||||||
|
&PointerEvent{},
|
||||||
|
&ClientCutText{},
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerInit struct {
|
||||||
|
FBWidth, FBHeight uint16
|
||||||
|
PixelFormat common.PixelFormat
|
||||||
|
NameLength uint32
|
||||||
|
NameText []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
//var _ Conn = (*ServerConn)(nil)
|
||||||
|
|
||||||
|
// ServerMessage represents a Client-to-Server RFB message type.
|
||||||
|
// type ServerMessageType uint8
|
||||||
|
|
||||||
|
// //go:generate stringer -type=ServerMessageType
|
||||||
|
|
||||||
|
// // Client-to-Server message types.
|
||||||
|
// const (
|
||||||
|
// FramebufferUpdateMsgType ServerMessageType = iota
|
||||||
|
// SetColorMapEntriesMsgType
|
||||||
|
// BellMsgType
|
||||||
|
// ServerCutTextMsgType
|
||||||
|
// )
|
||||||
|
|
||||||
|
// FramebufferUpdate holds a FramebufferUpdate wire format message.
|
||||||
|
type FramebufferUpdate struct {
|
||||||
|
_ [1]byte // pad
|
||||||
|
NumRect uint16 // number-of-rectangles
|
||||||
|
Rects []*common.Rectangle // rectangles
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (*FramebufferUpdate) Type() ServerMessageType {
|
||||||
|
// return FramebufferUpdateMsgType
|
||||||
|
// }
|
||||||
|
|
||||||
|
type ServerHandler func(*ServerConfig, *ServerConn) error
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
//VersionHandler ServerHandler
|
||||||
|
//SecurityHandler ServerHandler
|
||||||
|
SecurityHandlers []SecurityHandler
|
||||||
|
//ClientInitHandler ServerHandler
|
||||||
|
//ServerInitHandler ServerHandler
|
||||||
|
Encodings []common.Encoding
|
||||||
|
PixelFormat *common.PixelFormat
|
||||||
|
ColorMap *common.ColorMap
|
||||||
|
ClientMessageCh chan common.ClientMessage
|
||||||
|
ServerMessageCh chan common.ServerMessage
|
||||||
|
ClientMessages []common.ClientMessage
|
||||||
|
DesktopName []byte
|
||||||
|
Height uint16
|
||||||
|
Width uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) {
|
||||||
|
if cfg.ClientMessageCh == nil {
|
||||||
|
return nil, fmt.Errorf("ClientMessageCh nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.ClientMessages) == 0 {
|
||||||
|
return nil, fmt.Errorf("ClientMessage 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ServerConn{
|
||||||
|
c: c,
|
||||||
|
br: bufio.NewReader(c),
|
||||||
|
bw: bufio.NewWriter(c),
|
||||||
|
cfg: cfg,
|
||||||
|
quit: make(chan struct{}),
|
||||||
|
encodings: cfg.Encodings,
|
||||||
|
pixelFormat: cfg.PixelFormat,
|
||||||
|
fbWidth: cfg.Width,
|
||||||
|
fbHeight: cfg.Height,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Serve(ctx context.Context, ln net.Listener, cfg *ServerConfig) error {
|
||||||
|
for {
|
||||||
|
|
||||||
|
c, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := NewServerConn(c, cfg)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ServerVersionHandler(cfg, conn); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ServerSecurityHandler(cfg, conn); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ServerClientInitHandler(cfg, conn); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ServerServerInitHandler(cfg, conn); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go conn.Handle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) Handle() error {
|
||||||
|
//var err error
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
//create a map of all message types
|
||||||
|
clientMessages := make(map[common.ClientMessageType]common.ClientMessage)
|
||||||
|
for _, m := range c.cfg.ClientMessages {
|
||||||
|
clientMessages[m.Type()] = m
|
||||||
|
}
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
// server
|
||||||
|
go func() error {
|
||||||
|
defer wg.Done()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg := <-c.cfg.ServerMessageCh:
|
||||||
|
fmt.Printf("%v", msg)
|
||||||
|
// if err = msg.Write(c); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
case <-c.quit:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// client
|
||||||
|
go func() error {
|
||||||
|
defer wg.Done()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.quit:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
var messageType common.ClientMessageType
|
||||||
|
if err := binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msg, ok := clientMessages[messageType]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unsupported message-type: %v", messageType)
|
||||||
|
|
||||||
|
}
|
||||||
|
parsedMsg, err := msg.Read(c)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("srv err %s\n", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("message:%s, %v\n",parsedMsg.Type(), parsedMsg)
|
||||||
|
//c.cfg.ClientMessageCh <- parsedMsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// type ServerCutText struct {
|
||||||
|
// _ [1]byte
|
||||||
|
// Length uint32
|
||||||
|
// Text []byte
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*ServerCutText) Type() ServerMessageType {
|
||||||
|
// return ServerCutTextMsgType
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*ServerCutText) Read(c common.Conn) (common.ServerMessage, error) {
|
||||||
|
// msg := ServerCutText{}
|
||||||
|
|
||||||
|
// var pad [1]byte
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &msg.Length); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// msg.Text = make([]byte, msg.Length)
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &msg.Text); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// return &msg, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (msg *ServerCutText) Write(c common.Conn) error {
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// var pad [1]byte
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if msg.Length < uint32(len(msg.Text)) {
|
||||||
|
// msg.Length = uint32(len(msg.Text))
|
||||||
|
// }
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.Length); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.Text); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type Bell struct{}
|
||||||
|
|
||||||
|
// func (*Bell) Type() ServerMessageType {
|
||||||
|
// return BellMsgType
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*Bell) Read(c common.Conn) (common.ServerMessage, error) {
|
||||||
|
// return &Bell{}, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (msg *Bell) Write(c common.Conn) error {
|
||||||
|
// return binary.Write(c, binary.BigEndian, msg.Type())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type SetColorMapEntries struct {
|
||||||
|
// _ [1]byte
|
||||||
|
// FirstColor uint16
|
||||||
|
// ColorsNum uint16
|
||||||
|
// Colors []common.Color
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*SetColorMapEntries) Type() ServerMessageType {
|
||||||
|
// return SetColorMapEntriesMsgType
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*SetColorMapEntries) Read(c common.Conn) (common.ServerMessage, error) {
|
||||||
|
// msg := SetColorMapEntries{}
|
||||||
|
// var pad [1]byte
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &msg.FirstColor); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &msg.ColorsNum); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// msg.Colors = make([]common.Color, msg.ColorsNum)
|
||||||
|
// colorMap := c.ColorMap()
|
||||||
|
|
||||||
|
// for i := uint16(0); i < msg.ColorsNum; i++ {
|
||||||
|
// color := &msg.Colors[i]
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &color); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// colorMap[msg.FirstColor+i] = *color
|
||||||
|
// }
|
||||||
|
// c.SetColorMap(colorMap)
|
||||||
|
// return &msg, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (msg *SetColorMapEntries) Write(c common.Conn) error {
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// var pad [1]byte
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.FirstColor); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if msg.ColorsNum < uint16(len(msg.Colors)) {
|
||||||
|
// msg.ColorsNum = uint16(len(msg.Colors))
|
||||||
|
// }
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.ColorsNum); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for i := 0; i < len(msg.Colors); i++ {
|
||||||
|
// color := msg.Colors[i]
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, color); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (*FramebufferUpdate) Read(cliInfo common.IClientConn, c *common.RfbReadHelper) (common.ServerMessage, error) {
|
||||||
|
// msg := FramebufferUpdate{}
|
||||||
|
// var pad [1]byte
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := binary.Read(c, binary.BigEndian, &msg.NumRect); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// for i := uint16(0); i < msg.NumRect; i++ {
|
||||||
|
// rect := &common.Rectangle{}
|
||||||
|
// if err := rect.Read(c); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// msg.Rects = append(msg.Rects, rect)
|
||||||
|
// }
|
||||||
|
// return &msg, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (msg *FramebufferUpdate) Write(c common.Conn) error {
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// var pad [1]byte
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err := binary.Write(c, binary.BigEndian, msg.NumRect); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// for _, rect := range msg.Rects {
|
||||||
|
// if err := rect.Write(c); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return c.Flush()
|
||||||
|
// }
|
44
server/server_test.go
Normal file
44
server/server_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
"vncproxy/common"
|
||||||
|
"vncproxy/encodings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServer(t *testing.T) {
|
||||||
|
ln, err := net.Listen("tcp", ":5903")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error listen. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chServer := make(chan common.ClientMessage)
|
||||||
|
chClient := make(chan common.ServerMessage)
|
||||||
|
|
||||||
|
cfg := &ServerConfig{
|
||||||
|
//SecurityHandlers: []SecurityHandler{&ServerAuthNone{}, &ServerAuthVNC{}},
|
||||||
|
SecurityHandlers: []SecurityHandler{&ServerAuthVNC{}},
|
||||||
|
Encodings: []common.Encoding{&encodings.RawEncoding{}, &encodings.TightEncoding{}, &encodings.CopyRectEncoding{}},
|
||||||
|
PixelFormat: common.NewPixelFormat(32),
|
||||||
|
ClientMessageCh: chServer,
|
||||||
|
ServerMessageCh: chClient,
|
||||||
|
ClientMessages: DefaultClientMessages,
|
||||||
|
DesktopName: []byte("workDesk"),
|
||||||
|
Height: uint16(768),
|
||||||
|
Width: uint16(1024),
|
||||||
|
|
||||||
|
}
|
||||||
|
go Serve(context.Background(), ln, cfg)
|
||||||
|
|
||||||
|
// Process messages coming in on the ClientMessage channel.
|
||||||
|
for {
|
||||||
|
msg := <-chClient
|
||||||
|
switch msg.Type() {
|
||||||
|
default:
|
||||||
|
log.Printf("Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,15 +12,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// A ServerMessage implements a message sent from the server to the client.
|
// A ServerMessage implements a message sent from the server to the client.
|
||||||
type ServerMessage interface {
|
|
||||||
// The type of the message that is sent down on the wire.
|
|
||||||
Type() uint8
|
|
||||||
String() string
|
|
||||||
// Read reads the contents of the message from the reader. At the point
|
|
||||||
// this is called, the message type has already been read from the reader.
|
|
||||||
// This should return a new ServerMessage that is the appropriate type.
|
|
||||||
Read(*ClientConn, *common.RfbReadHelper) (ServerMessage, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A ClientAuth implements a method of authenticating with a remote server.
|
// A ClientAuth implements a method of authenticating with a remote server.
|
||||||
type ClientAuth interface {
|
type ClientAuth interface {
|
||||||
@ -42,7 +33,7 @@ type ClientConn struct {
|
|||||||
// If the pixel format uses a color map, then this is the color
|
// If the pixel format uses a color map, then this is the color
|
||||||
// map that is used. This should not be modified directly, since
|
// map that is used. This should not be modified directly, since
|
||||||
// the data comes from the server.
|
// the data comes from the server.
|
||||||
ColorMap [256]Color
|
ColorMap common.ColorMap
|
||||||
|
|
||||||
// Encodings supported by the client. This should not be modified
|
// Encodings supported by the client. This should not be modified
|
||||||
// directly. Instead, SetEncodings should be used.
|
// directly. Instead, SetEncodings should be used.
|
||||||
@ -80,12 +71,12 @@ type ClientConfig struct {
|
|||||||
// from the VNC server may block indefinitely. It is up to the user
|
// from the VNC server may block indefinitely. It is up to the user
|
||||||
// of the library to ensure that this channel is properly read.
|
// of the library to ensure that this channel is properly read.
|
||||||
// If this is not set, then all messages will be discarded.
|
// If this is not set, then all messages will be discarded.
|
||||||
ServerMessageCh chan<- ServerMessage
|
ServerMessageCh chan<- common.ServerMessage
|
||||||
|
|
||||||
// A slice of supported messages that can be read from the server.
|
// A slice of supported messages that can be read from the server.
|
||||||
// This only needs to contain NEW server messages, and doesn't
|
// This only needs to contain NEW server messages, and doesn't
|
||||||
// need to explicitly contain the RFC-required messages.
|
// need to explicitly contain the RFC-required messages.
|
||||||
ServerMessages []ServerMessage
|
ServerMessages []common.ServerMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
func Client(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
func Client(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||||
@ -108,6 +99,18 @@ func (c *ClientConn) Close() error {
|
|||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClientConn) Encodings() []common.Encoding {
|
||||||
|
return c.Encs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClientConn) CurrentPixelFormat() *common.PixelFormat {
|
||||||
|
return &c.PixelFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClientConn) CurrentColorMap() *common.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
|
||||||
// is compatible with Go's native string format, but can only use up to
|
// is compatible with Go's native string format, but can only use up to
|
||||||
@ -295,7 +298,7 @@ func (c *ClientConn) SetPixelFormat(format *common.PixelFormat) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset the color map as according to RFC.
|
// Reset the color map as according to RFC.
|
||||||
var newColorMap [256]Color
|
var newColorMap common.ColorMap
|
||||||
c.ColorMap = newColorMap
|
c.ColorMap = newColorMap
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -447,9 +450,9 @@ func (c *ClientConn) mainLoop() {
|
|||||||
|
|
||||||
reader := &common.RfbReadHelper{Reader: c.conn, Listener: rec}
|
reader := &common.RfbReadHelper{Reader: c.conn, Listener: rec}
|
||||||
// Build the map of available server messages
|
// Build the map of available server messages
|
||||||
typeMap := make(map[uint8]ServerMessage)
|
typeMap := make(map[uint8]common.ServerMessage)
|
||||||
|
|
||||||
defaultMessages := []ServerMessage{
|
defaultMessages := []common.ServerMessage{
|
||||||
new(FramebufferUpdateMessage),
|
new(FramebufferUpdateMessage),
|
||||||
new(SetColorMapEntriesMessage),
|
new(SetColorMapEntriesMessage),
|
||||||
new(BellMessage),
|
new(BellMessage),
|
||||||
@ -477,7 +480,7 @@ func (c *ClientConn) mainLoop() {
|
|||||||
// Unsupported message type! Bad!
|
// Unsupported message type! Bad!
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
reader.SendMessageSeparator(int(messageType))
|
reader.SendMessageSeparator(common.ServerMessageType(messageType))
|
||||||
reader.PublishBytes([]byte{byte(messageType)})
|
reader.PublishBytes([]byte{byte(messageType)})
|
||||||
|
|
||||||
parsedMsg, err := msg.Read(c, reader)
|
parsedMsg, err := msg.Read(c, reader)
|
||||||
|
@ -27,7 +27,7 @@ func (*FramebufferUpdateMessage) Type() uint8 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fbm *FramebufferUpdateMessage) Read(c *ClientConn, r *common.RfbReadHelper) (ServerMessage, error) {
|
func (fbm *FramebufferUpdateMessage) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
||||||
|
|
||||||
// Read off the padding
|
// Read off the padding
|
||||||
var padding [1]byte
|
var padding [1]byte
|
||||||
@ -42,7 +42,7 @@ func (fbm *FramebufferUpdateMessage) Read(c *ClientConn, r *common.RfbReadHelper
|
|||||||
|
|
||||||
// Build the map of encodings supported
|
// Build the map of encodings supported
|
||||||
encMap := make(map[int32]common.Encoding)
|
encMap := make(map[int32]common.Encoding)
|
||||||
for _, enc := range c.Encs {
|
for _, enc := range c.Encodings() {
|
||||||
encMap[enc.Type()] = enc
|
encMap[enc.Type()] = enc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ func (fbm *FramebufferUpdateMessage) Read(c *ClientConn, r *common.RfbReadHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
rect.Enc, err = enc.Read(&c.PixelFormat, rect, r)
|
rect.Enc, err = enc.Read(c.CurrentPixelFormat(), rect, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ func (fbm *FramebufferUpdateMessage) Read(c *ClientConn, r *common.RfbReadHelper
|
|||||||
// See RFC 6143 Section 7.6.2
|
// See RFC 6143 Section 7.6.2
|
||||||
type SetColorMapEntriesMessage struct {
|
type SetColorMapEntriesMessage struct {
|
||||||
FirstColor uint16
|
FirstColor uint16
|
||||||
Colors []Color
|
Colors []common.Color
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SetColorMapEntriesMessage) String() string {
|
func (m *SetColorMapEntriesMessage) String() string {
|
||||||
@ -110,7 +110,7 @@ func (*SetColorMapEntriesMessage) Type() uint8 {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*SetColorMapEntriesMessage) Read(c *ClientConn, r *common.RfbReadHelper) (ServerMessage, error) {
|
func (*SetColorMapEntriesMessage) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
||||||
// Read off the padding
|
// Read off the padding
|
||||||
var padding [1]byte
|
var padding [1]byte
|
||||||
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||||||
@ -127,7 +127,7 @@ func (*SetColorMapEntriesMessage) Read(c *ClientConn, r *common.RfbReadHelper) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Colors = make([]Color, numColors)
|
result.Colors = make([]common.Color, numColors)
|
||||||
for i := uint16(0); i < numColors; i++ {
|
for i := uint16(0); i < numColors; i++ {
|
||||||
|
|
||||||
color := &result.Colors[i]
|
color := &result.Colors[i]
|
||||||
@ -142,9 +142,9 @@ func (*SetColorMapEntriesMessage) Read(c *ClientConn, r *common.RfbReadHelper) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cmap := c.CurrentColorMap()
|
||||||
// Update the connection's color map
|
// Update the connection's color map
|
||||||
c.ColorMap[result.FirstColor+i] = *color
|
cmap[result.FirstColor+i] = *color
|
||||||
}
|
}
|
||||||
|
|
||||||
return &result, nil
|
return &result, nil
|
||||||
@ -163,7 +163,7 @@ func (*BellMessage) Type() uint8 {
|
|||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*BellMessage) Read(*ClientConn, *common.RfbReadHelper) (ServerMessage, error) {
|
func (*BellMessage) Read(common.IClientConn, *common.RfbReadHelper) (common.ServerMessage, error) {
|
||||||
return new(BellMessage), nil
|
return new(BellMessage), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ func (*ServerCutTextMessage) Type() uint8 {
|
|||||||
return 3
|
return 3
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ServerCutTextMessage) Read(conn *ClientConn, r *common.RfbReadHelper) (ServerMessage, error) {
|
func (*ServerCutTextMessage) Read(conn common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
||||||
//reader := common.RfbReadHelper{Reader: r}
|
//reader := common.RfbReadHelper{Reader: r}
|
||||||
|
|
||||||
// Read off the padding
|
// Read off the padding
|
Loading…
Reference in New Issue
Block a user