diff --git a/.idea/libraries/GOPATH__vncproxy_.xml b/.idea/libraries/GOPATH__vncproxy_.xml index de67345..7c966c1 100644 --- a/.idea/libraries/GOPATH__vncproxy_.xml +++ b/.idea/libraries/GOPATH__vncproxy_.xml @@ -5,6 +5,7 @@ + @@ -26,6 +27,7 @@ + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 4d2d2ba..14ccde0 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,27 +2,30 @@ - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - + - + + + + + - + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + @@ -71,49 +98,32 @@ - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -121,8 +131,32 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -130,21 +164,15 @@ + + + - PixelFormat - setpixrl - writePixelFormat - nil, - binary.Write - WaitGroup - SetPixelFormat - authtext - ServerConfig - serverinit - uint16 - writeto - ServerServerInitHandler r rfhc rfh @@ -162,6 +190,19 @@ mainLoop NewServerConn Serve + uint16 + l + client + tcp + ln + client. + se + secur + securi + auth + c. + upgrade + read @@ -179,10 +220,16 @@ @@ -197,6 +244,22 @@ + + + + + + + + + + + Android + + + + + @@ -212,6 +275,9 @@ + + + @@ -219,8 +285,30 @@ + + + + + + + @@ -230,11 +318,57 @@ - - - + + + @@ -774,46 +908,60 @@ 1497962309959 + + + + + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + - + @@ -829,9 +977,8 @@ - + - @@ -842,9 +989,11 @@ + + @@ -872,59 +1021,24 @@ file://$PROJECT_DIR$/server/server_test.go - 39 + 30 file://$PROJECT_DIR$/server/server_test.go - 41 + 31 file://$PROJECT_DIR$/server/server.go - 156 + 222 file://$PROJECT_DIR$/server/server.go - 166 + 226 - - file://$PROJECT_DIR$/server/server.go - 169 - - - file://$PROJECT_DIR$/server/server.go - 175 - - - file://$PROJECT_DIR$/server/server.go - 180 - - - file://$PROJECT_DIR$/server/server.go - 140 - - - file://$PROJECT_DIR$/server/server.go - 141 - - - file://$PROJECT_DIR$/server/server.go - 139 - - - file://$PROJECT_DIR$/server/security.go - 199 - file://$PROJECT_DIR$/common/encoding.go 164 @@ -932,104 +1046,167 @@ file://$PROJECT_DIR$/server/server.go - 124 + 169 file://$PROJECT_DIR$/server/server.go - 163 - - - file://$PROJECT_DIR$/server/security.go - 213 - - - file://$PROJECT_DIR$/server/security.go - 216 - - - file://$PROJECT_DIR$/server/security.go - 218 - - - file://$PROJECT_DIR$/server/security.go - 217 - - - file://$PROJECT_DIR$/server/security.go - 210 - - - file://$PROJECT_DIR$/server/server.go - 136 + 202 file://$PROJECT_DIR$/server/server.go - 134 + 200 file://$PROJECT_DIR$/server/server.go - 151 + 213 - - file://$PROJECT_DIR$/server/server.go - 170 - file://$PROJECT_DIR$/server/server.go 173 - - - file://$PROJECT_DIR$/server/server.go - 147 - - - file://$PROJECT_DIR$/server/server.go - 171 - - - file://$PROJECT_DIR$/server/server.go - 128 - + + file://$PROJECT_DIR$/server/ws-server-gorilla.go + 98 + + + file://$PROJECT_DIR$/../github.com/gorilla/websocket/server.go + 219 + + + file://$PROJECT_DIR$/server/ws-server-go.go + 35 + + + file://$PROJECT_DIR$/server/ws-server-go.go + 23 + file://$PROJECT_DIR$/server/server.go - 178 - - + + file://$PROJECT_DIR$/server/server.go + 207 + + + file://$PROJECT_DIR$/server/server.go + 205 + + + file://$PROJECT_DIR$/server/server.go + 185 + + + file://$PROJECT_DIR$/server/server.go + 190 + + + file://$PROJECT_DIR$/server/server.go + 209 + + + file://$PROJECT_DIR$/server/server.go + 211 + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -1045,7 +1222,10 @@ - + + + + @@ -1053,25 +1233,6 @@ - - - - - - - - - - - - - - - - - - - @@ -1083,11 +1244,10 @@ - + - @@ -1095,34 +1255,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1141,36 +1273,103 @@ - + - + - - - + - - - - - + + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1179,163 +1378,114 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + - + + + + + - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/vnc/README.md b/client/README.md similarity index 100% rename from vnc/README.md rename to client/README.md diff --git a/vnc/client-conn.go b/client/client-conn.go similarity index 99% rename from vnc/client-conn.go rename to client/client-conn.go index 8ed6f93..ec8b75e 100644 --- a/vnc/client-conn.go +++ b/client/client-conn.go @@ -1,4 +1,4 @@ -package vnc +package client import ( "bytes" @@ -8,7 +8,7 @@ import ( "net" "unicode" "vncproxy/common" - "vncproxy/listeners" + "vncproxy/tee-listeners" ) // A ServerMessage implements a message sent from the server to the client. diff --git a/vnc/client_auth.go b/client/client_auth.go similarity index 95% rename from vnc/client_auth.go rename to client/client_auth.go index 1b6a48e..8a59857 100644 --- a/vnc/client_auth.go +++ b/client/client_auth.go @@ -1,114 +1,114 @@ -package vnc - -import ( - "net" - - "crypto/des" - "encoding/binary" -) - - -// ClientAuthNone is the "none" authentication. See 7.2.1 -type ClientAuthNone byte - -func (*ClientAuthNone) SecurityType() uint8 { - return 1 -} - -func (*ClientAuthNone) Handshake(net.Conn) error { - return nil -} - -// PasswordAuth is VNC authentication, 7.2.2 -type PasswordAuth struct { - Password string -} - -func (p *PasswordAuth) SecurityType() uint8 { - return 2 -} - -func (p *PasswordAuth) Handshake(c net.Conn) error { - randomValue := make([]uint8, 16) - if err := binary.Read(c, binary.BigEndian, &randomValue); err != nil { - return err - } - - crypted, err := p.encrypt(p.Password, randomValue) - - if (err != nil) { - return err - } - - if err := binary.Write(c, binary.BigEndian, &crypted); err != nil { - return err - } - - return nil -} - -func (p *PasswordAuth) reverseBits(b byte) byte { - var reverse = [256]int{ - 0, 128, 64, 192, 32, 160, 96, 224, - 16, 144, 80, 208, 48, 176, 112, 240, - 8, 136, 72, 200, 40, 168, 104, 232, - 24, 152, 88, 216, 56, 184, 120, 248, - 4, 132, 68, 196, 36, 164, 100, 228, - 20, 148, 84, 212, 52, 180, 116, 244, - 12, 140, 76, 204, 44, 172, 108, 236, - 28, 156, 92, 220, 60, 188, 124, 252, - 2, 130, 66, 194, 34, 162, 98, 226, - 18, 146, 82, 210, 50, 178, 114, 242, - 10, 138, 74, 202, 42, 170, 106, 234, - 26, 154, 90, 218, 58, 186, 122, 250, - 6, 134, 70, 198, 38, 166, 102, 230, - 22, 150, 86, 214, 54, 182, 118, 246, - 14, 142, 78, 206, 46, 174, 110, 238, - 30, 158, 94, 222, 62, 190, 126, 254, - 1, 129, 65, 193, 33, 161, 97, 225, - 17, 145, 81, 209, 49, 177, 113, 241, - 9, 137, 73, 201, 41, 169, 105, 233, - 25, 153, 89, 217, 57, 185, 121, 249, - 5, 133, 69, 197, 37, 165, 101, 229, - 21, 149, 85, 213, 53, 181, 117, 245, - 13, 141, 77, 205, 45, 173, 109, 237, - 29, 157, 93, 221, 61, 189, 125, 253, - 3, 131, 67, 195, 35, 163, 99, 227, - 19, 147, 83, 211, 51, 179, 115, 243, - 11, 139, 75, 203, 43, 171, 107, 235, - 27, 155, 91, 219, 59, 187, 123, 251, - 7, 135, 71, 199, 39, 167, 103, 231, - 23, 151, 87, 215, 55, 183, 119, 247, - 15, 143, 79, 207, 47, 175, 111, 239, - 31, 159, 95, 223, 63, 191, 127, 255, - } - - return byte(reverse[int(b)]) -} - -func (p *PasswordAuth) encrypt(key string, bytes []byte) ([]byte, error) { - keyBytes := []byte{0,0,0,0,0,0,0,0} - - if len(key) > 8 { - key = key[:8] - } - - for i := 0; i < len(key); i++ { - keyBytes[i] = p.reverseBits(key[i]) - } - - block, err := des.NewCipher(keyBytes) - - if err != nil { - return nil, err - } - - result1 := make([]byte, 8) - block.Encrypt(result1, bytes) - result2 := make([]byte, 8) - block.Encrypt(result2, bytes[8:]) - - crypted := append(result1, result2...) - - return crypted, nil -} +package client + +import ( + "net" + + "crypto/des" + "encoding/binary" +) + + +// ClientAuthNone is the "none" authentication. See 7.2.1 +type ClientAuthNone byte + +func (*ClientAuthNone) SecurityType() uint8 { + return 1 +} + +func (*ClientAuthNone) Handshake(net.Conn) error { + return nil +} + +// PasswordAuth is VNC authentication, 7.2.2 +type PasswordAuth struct { + Password string +} + +func (p *PasswordAuth) SecurityType() uint8 { + return 2 +} + +func (p *PasswordAuth) Handshake(c net.Conn) error { + randomValue := make([]uint8, 16) + if err := binary.Read(c, binary.BigEndian, &randomValue); err != nil { + return err + } + + crypted, err := p.encrypt(p.Password, randomValue) + + if (err != nil) { + return err + } + + if err := binary.Write(c, binary.BigEndian, &crypted); err != nil { + return err + } + + return nil +} + +func (p *PasswordAuth) reverseBits(b byte) byte { + var reverse = [256]int{ + 0, 128, 64, 192, 32, 160, 96, 224, + 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, + 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, + 20, 148, 84, 212, 52, 180, 116, 244, + 12, 140, 76, 204, 44, 172, 108, 236, + 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, + 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, + 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, + 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, + 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, + 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, + 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, + 21, 149, 85, 213, 53, 181, 117, 245, + 13, 141, 77, 205, 45, 173, 109, 237, + 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, + 19, 147, 83, 211, 51, 179, 115, 243, + 11, 139, 75, 203, 43, 171, 107, 235, + 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, + 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, + 31, 159, 95, 223, 63, 191, 127, 255, + } + + return byte(reverse[int(b)]) +} + +func (p *PasswordAuth) encrypt(key string, bytes []byte) ([]byte, error) { + keyBytes := []byte{0,0,0,0,0,0,0,0} + + if len(key) > 8 { + key = key[:8] + } + + for i := 0; i < len(key); i++ { + keyBytes[i] = p.reverseBits(key[i]) + } + + block, err := des.NewCipher(keyBytes) + + if err != nil { + return nil, err + } + + result1 := make([]byte, 8) + block.Encrypt(result1, bytes) + result2 := make([]byte, 8) + block.Encrypt(result2, bytes[8:]) + + crypted := append(result1, result2...) + + return crypted, nil +} diff --git a/vnc/client_auth_test.go b/client/client_auth_test.go similarity index 94% rename from vnc/client_auth_test.go rename to client/client_auth_test.go index 412e041..1858400 100644 --- a/vnc/client_auth_test.go +++ b/client/client_auth_test.go @@ -1,169 +1,169 @@ -package vnc - -import ( - "testing" - "net" - "time" - "bytes" -) - -type fakeNetConnection struct { - DataToSend []byte - Test *testing.T - ExpectData []byte - Finished bool - Matched bool -} - -func (fc fakeNetConnection) Read(b []byte) (n int, err error) { - for i := 0; i < 16; i++ { - b[i] = fc.DataToSend[i] - } - - fc.Finished = false - - return len(b), nil -} - -func (fc *fakeNetConnection) Write(b []byte) (n int, err error) { - fc.Matched = bytes.Equal(b, fc.ExpectData) - fc.Finished = true - - return len(b), nil -} - -func (fc *fakeNetConnection) Close() error { return nil; } -func (fc *fakeNetConnection) LocalAddr() net.Addr { return nil; } -func (fc *fakeNetConnection) RemoteAddr() net.Addr { return nil; } -func (fc *fakeNetConnection) SetDeadline(t time.Time) error { return nil; } -func (fc *fakeNetConnection) SetReadDeadline(t time.Time) error { return nil; } -func (fc *fakeNetConnection) SetWriteDeadline(t time.Time) error { return nil; } - -func TestClientAuthNone_Impl(t *testing.T) { - var raw interface{} - raw = new(ClientAuthNone) - if _, ok := raw.(ClientAuth); !ok { - t.Fatal("ClientAuthNone doesn't implement ClientAuth") - } -} - -func TestClientAuthPasswordSuccess_Impl(t *testing.T) { - // Values ripped using WireShark - randomValue := []byte{ - 0xa4, - 0x51, - 0x3f, - 0xa5, - 0x1f, - 0x87, - 0x06, - 0x10, - 0xa4, - 0x5f, - 0xae, - 0xbf, - 0x4d, - 0xac, - 0x12, - 0x22, - } - - expectedResponse := []byte{ - 0x71, - 0xe4, - 0x41, - 0x30, - 0x43, - 0x65, - 0x4e, - 0x39, - 0xda, - 0x6d, - 0x49, - 0x93, - 0x43, - 0xf6, - 0x5e, - 0x29, - } - - raw := PasswordAuth{Password: "Ch_#!T@8"} - - // Only about 12 hours into Go at the moment... - // if _, ok := raw.(ClientAuth); !ok { - // t.Fatal("PasswordAuth doesn't implement ClientAuth") - // } - - conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t} - err := raw.Handshake(conn) - - if (err != nil) { - t.Fatal(err) - } - - if !conn.Matched { - t.Fatal("PasswordAuth didn't pass the right response back to the wire") - } - - if !conn.Finished { - t.Fatal("PasswordAuth didn't complete properly") - } -} - -func TestClientAuthPasswordReject_Impl(t *testing.T) { - // Values ripped using WireShark - randomValue := []byte{ - 0xa4, - 0x51, - 0x3f, - 0xa5, - 0x1f, - 0x87, - 0x06, - 0x10, - 0xa4, - 0x5f, - 0xae, - 0xbf, - 0x4d, - 0xac, - 0x12, - 0x22, - } - - expectedResponse := []byte{ - 0x71, - 0xe4, - 0x41, - 0x30, - 0x43, - 0x65, - 0x4e, - 0x39, - 0xda, - 0x6d, - 0x49, - 0x93, - 0x43, - 0xf6, - 0x5e, - 0x29, - } - - raw := PasswordAuth{Password: "Ch_#!T@"} - - conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t} - err := raw.Handshake(conn) - - if (err != nil) { - t.Fatal(err) - } - - if conn.Matched { - t.Fatal("PasswordAuth didn't pass the right response back to the wire") - } - - if !conn.Finished { - t.Fatal("PasswordAuth didn't complete properly") - } +package client + +import ( + "testing" + "net" + "time" + "bytes" +) + +type fakeNetConnection struct { + DataToSend []byte + Test *testing.T + ExpectData []byte + Finished bool + Matched bool +} + +func (fc fakeNetConnection) Read(b []byte) (n int, err error) { + for i := 0; i < 16; i++ { + b[i] = fc.DataToSend[i] + } + + fc.Finished = false + + return len(b), nil +} + +func (fc *fakeNetConnection) Write(b []byte) (n int, err error) { + fc.Matched = bytes.Equal(b, fc.ExpectData) + fc.Finished = true + + return len(b), nil +} + +func (fc *fakeNetConnection) Close() error { return nil; } +func (fc *fakeNetConnection) LocalAddr() net.Addr { return nil; } +func (fc *fakeNetConnection) RemoteAddr() net.Addr { return nil; } +func (fc *fakeNetConnection) SetDeadline(t time.Time) error { return nil; } +func (fc *fakeNetConnection) SetReadDeadline(t time.Time) error { return nil; } +func (fc *fakeNetConnection) SetWriteDeadline(t time.Time) error { return nil; } + +func TestClientAuthNone_Impl(t *testing.T) { + var raw interface{} + raw = new(ClientAuthNone) + if _, ok := raw.(ClientAuth); !ok { + t.Fatal("ClientAuthNone doesn't implement ClientAuth") + } +} + +func TestClientAuthPasswordSuccess_Impl(t *testing.T) { + // Values ripped using WireShark + randomValue := []byte{ + 0xa4, + 0x51, + 0x3f, + 0xa5, + 0x1f, + 0x87, + 0x06, + 0x10, + 0xa4, + 0x5f, + 0xae, + 0xbf, + 0x4d, + 0xac, + 0x12, + 0x22, + } + + expectedResponse := []byte{ + 0x71, + 0xe4, + 0x41, + 0x30, + 0x43, + 0x65, + 0x4e, + 0x39, + 0xda, + 0x6d, + 0x49, + 0x93, + 0x43, + 0xf6, + 0x5e, + 0x29, + } + + raw := PasswordAuth{Password: "Ch_#!T@8"} + + // Only about 12 hours into Go at the moment... + // if _, ok := raw.(ClientAuth); !ok { + // t.Fatal("PasswordAuth doesn't implement ClientAuth") + // } + + conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t} + err := raw.Handshake(conn) + + if (err != nil) { + t.Fatal(err) + } + + if !conn.Matched { + t.Fatal("PasswordAuth didn't pass the right response back to the wire") + } + + if !conn.Finished { + t.Fatal("PasswordAuth didn't complete properly") + } +} + +func TestClientAuthPasswordReject_Impl(t *testing.T) { + // Values ripped using WireShark + randomValue := []byte{ + 0xa4, + 0x51, + 0x3f, + 0xa5, + 0x1f, + 0x87, + 0x06, + 0x10, + 0xa4, + 0x5f, + 0xae, + 0xbf, + 0x4d, + 0xac, + 0x12, + 0x22, + } + + expectedResponse := []byte{ + 0x71, + 0xe4, + 0x41, + 0x30, + 0x43, + 0x65, + 0x4e, + 0x39, + 0xda, + 0x6d, + 0x49, + 0x93, + 0x43, + 0xf6, + 0x5e, + 0x29, + } + + raw := PasswordAuth{Password: "Ch_#!T@"} + + conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t} + err := raw.Handshake(conn) + + if (err != nil) { + t.Fatal(err) + } + + if conn.Matched { + t.Fatal("PasswordAuth didn't pass the right response back to the wire") + } + + if !conn.Finished { + t.Fatal("PasswordAuth didn't complete properly") + } } \ No newline at end of file diff --git a/vnc/client_test.go b/client/client_test.go similarity index 95% rename from vnc/client_test.go rename to client/client_test.go index b414567..4233b5e 100644 --- a/vnc/client_test.go +++ b/client/client_test.go @@ -1,95 +1,95 @@ -package vnc - -import ( - "fmt" - "net" - "testing" -) - -func newMockServer(t *testing.T, version string) string { - ln, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("error listening: %s", err) - } - - go func() { - defer ln.Close() - c, err := ln.Accept() - if err != nil { - t.Fatalf("error accepting conn: %s", err) - } - defer c.Close() - - _, err = c.Write([]byte(fmt.Sprintf("RFB %s\n", version))) - if err != nil { - t.Fatal("failed writing version") - } - }() - - return ln.Addr().String() -} - -func TestClient_LowMajorVersion(t *testing.T) { - nc, err := net.Dial("tcp", newMockServer(t, "002.009")) - if err != nil { - t.Fatalf("error connecting to mock server: %s", err) - } - - _, err = Client(nc, &ClientConfig{}) - if err == nil { - t.Fatal("error expected") - } - - if err.Error() != "unsupported major version, less than 3: 2" { - t.Fatalf("unexpected error: %s", err) - } -} - -func TestClient_LowMinorVersion(t *testing.T) { - nc, err := net.Dial("tcp", newMockServer(t, "003.007")) - if err != nil { - t.Fatalf("error connecting to mock server: %s", err) - } - - _, err = Client(nc, &ClientConfig{}) - if err == nil { - t.Fatal("error expected") - } - - if err.Error() != "unsupported minor version, less than 8: 7" { - t.Fatalf("unexpected error: %s", err) - } -} - -func TestParseProtocolVersion(t *testing.T) { - tests := []struct { - proto []byte - major, minor uint - isErr bool - }{ - // Valid ProtocolVersion messages. - {[]byte{82, 70, 66, 32, 48, 48, 51, 46, 48, 48, 56, 10}, 3, 8, false}, // RFB 003.008\n - {[]byte{82, 70, 66, 32, 48, 48, 51, 46, 56, 56, 57, 10}, 3, 889, false}, // RFB 003.889\n -- OS X 10.10.3 - {[]byte{82, 70, 66, 32, 48, 48, 48, 46, 48, 48, 48, 10}, 0, 0, false}, // RFB 000.0000\n - // Invalid messages. - {[]byte{82, 70, 66, 32, 51, 46, 56, 10}, 0, 0, true}, // RFB 3.8\n -- too short; not zero padded - {[]byte{82, 70, 66, 10}, 0, 0, true}, // RFB\n -- too short - {[]byte{}, 0, 0, true}, // (empty) -- too short - } - - for _, tt := range tests { - major, minor, err := parseProtocolVersion(tt.proto) - if err != nil && !tt.isErr { - t.Fatalf("parseProtocolVersion(%v) unexpected error %v", tt.proto, err) - } - if err == nil && tt.isErr { - t.Fatalf("parseProtocolVersion(%v) expected error", tt.proto) - } - if major != tt.major { - t.Errorf("parseProtocolVersion(%v) major = %v, want %v", tt.proto, major, tt.major) - } - if major != tt.major { - t.Errorf("parseProtocolVersion(%v) minor = %v, want %v", tt.proto, minor, tt.minor) - } - } -} +package client + +import ( + "fmt" + "net" + "testing" +) + +func newMockServer(t *testing.T, version string) string { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("error listening: %s", err) + } + + go func() { + defer ln.Close() + c, err := ln.Accept() + if err != nil { + t.Fatalf("error accepting conn: %s", err) + } + defer c.Close() + + _, err = c.Write([]byte(fmt.Sprintf("RFB %s\n", version))) + if err != nil { + t.Fatal("failed writing version") + } + }() + + return ln.Addr().String() +} + +func TestClient_LowMajorVersion(t *testing.T) { + nc, err := net.Dial("tcp", newMockServer(t, "002.009")) + if err != nil { + t.Fatalf("error connecting to mock server: %s", err) + } + + _, err = Client(nc, &ClientConfig{}) + if err == nil { + t.Fatal("error expected") + } + + if err.Error() != "unsupported major version, less than 3: 2" { + t.Fatalf("unexpected error: %s", err) + } +} + +func TestClient_LowMinorVersion(t *testing.T) { + nc, err := net.Dial("tcp", newMockServer(t, "003.007")) + if err != nil { + t.Fatalf("error connecting to mock server: %s", err) + } + + _, err = Client(nc, &ClientConfig{}) + if err == nil { + t.Fatal("error expected") + } + + if err.Error() != "unsupported minor version, less than 8: 7" { + t.Fatalf("unexpected error: %s", err) + } +} + +func TestParseProtocolVersion(t *testing.T) { + tests := []struct { + proto []byte + major, minor uint + isErr bool + }{ + // Valid ProtocolVersion messages. + {[]byte{82, 70, 66, 32, 48, 48, 51, 46, 48, 48, 56, 10}, 3, 8, false}, // RFB 003.008\n + {[]byte{82, 70, 66, 32, 48, 48, 51, 46, 56, 56, 57, 10}, 3, 889, false}, // RFB 003.889\n -- OS X 10.10.3 + {[]byte{82, 70, 66, 32, 48, 48, 48, 46, 48, 48, 48, 10}, 0, 0, false}, // RFB 000.0000\n + // Invalid messages. + {[]byte{82, 70, 66, 32, 51, 46, 56, 10}, 0, 0, true}, // RFB 3.8\n -- too short; not zero padded + {[]byte{82, 70, 66, 10}, 0, 0, true}, // RFB\n -- too short + {[]byte{}, 0, 0, true}, // (empty) -- too short + } + + for _, tt := range tests { + major, minor, err := parseProtocolVersion(tt.proto) + if err != nil && !tt.isErr { + t.Fatalf("parseProtocolVersion(%v) unexpected error %v", tt.proto, err) + } + if err == nil && tt.isErr { + t.Fatalf("parseProtocolVersion(%v) expected error", tt.proto) + } + if major != tt.major { + t.Errorf("parseProtocolVersion(%v) major = %v, want %v", tt.proto, major, tt.major) + } + if major != tt.major { + t.Errorf("parseProtocolVersion(%v) minor = %v, want %v", tt.proto, minor, tt.minor) + } + } +} diff --git a/vnc/color.go b/client/color.go similarity index 83% rename from vnc/color.go rename to client/color.go index 7e45b56..a95dc89 100644 --- a/vnc/color.go +++ b/client/color.go @@ -1,6 +1,6 @@ -package vnc - -// Color represents a single color in a color map. -type Color struct { - R, G, B uint16 -} +package client + +// Color represents a single color in a color map. +type Color struct { + R, G, B uint16 +} diff --git a/client/debug.test b/client/debug.test new file mode 100644 index 0000000..7a1899d Binary files /dev/null and b/client/debug.test differ diff --git a/vnc/pixel-format.go b/client/pixel-format.go similarity index 95% rename from vnc/pixel-format.go rename to client/pixel-format.go index a9c8305..2e50f89 100644 --- a/vnc/pixel-format.go +++ b/client/pixel-format.go @@ -1,136 +1,136 @@ -package vnc - -import ( - "bytes" - "encoding/binary" - "io" - "vncproxy/common" -) - -func readPixelFormat(r io.Reader, result *common.PixelFormat) error { - var rawPixelFormat [16]byte - if _, err := io.ReadFull(r, rawPixelFormat[:]); err != nil { - return err - } - - var pfBoolByte uint8 - brPF := bytes.NewReader(rawPixelFormat[:]) - if err := binary.Read(brPF, binary.BigEndian, &result.BPP); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &result.Depth); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { - return err - } - - if pfBoolByte != 0 { - // Big endian is true - result.BigEndian = true - } - - if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { - return err - } - - if pfBoolByte != 0 { - // True Color is true. So we also have to read all the color max & shifts. - result.TrueColor = true - - if err := binary.Read(brPF, binary.BigEndian, &result.RedMax); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &result.GreenMax); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &result.BlueMax); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &result.RedShift); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &result.GreenShift); err != nil { - return err - } - - if err := binary.Read(brPF, binary.BigEndian, &result.BlueShift); err != nil { - return err - } - } - - return nil -} - -func writePixelFormat(format *common.PixelFormat) ([]byte, error) { - var buf bytes.Buffer - - // Byte 1 - if err := binary.Write(&buf, binary.BigEndian, format.BPP); err != nil { - return nil, err - } - - // Byte 2 - if err := binary.Write(&buf, binary.BigEndian, format.Depth); err != nil { - return nil, 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 nil, err - } - - if format.TrueColor { - boolByte = 1 - } else { - boolByte = 0 - } - - // Byte 4 (TrueColor) - if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil { - return nil, 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 nil, err - } - - if err := binary.Write(&buf, binary.BigEndian, format.GreenMax); err != nil { - return nil, err - } - - if err := binary.Write(&buf, binary.BigEndian, format.BlueMax); err != nil { - return nil, err - } - - if err := binary.Write(&buf, binary.BigEndian, format.RedShift); err != nil { - return nil, err - } - - if err := binary.Write(&buf, binary.BigEndian, format.GreenShift); err != nil { - return nil, err - } - - if err := binary.Write(&buf, binary.BigEndian, format.BlueShift); err != nil { - return nil, err - } - } - - return buf.Bytes()[0:16], nil -} +package client + +import ( + "bytes" + "encoding/binary" + "io" + "vncproxy/common" +) + +func readPixelFormat(r io.Reader, result *common.PixelFormat) error { + var rawPixelFormat [16]byte + if _, err := io.ReadFull(r, rawPixelFormat[:]); err != nil { + return err + } + + var pfBoolByte uint8 + brPF := bytes.NewReader(rawPixelFormat[:]) + if err := binary.Read(brPF, binary.BigEndian, &result.BPP); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &result.Depth); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { + return err + } + + if pfBoolByte != 0 { + // Big endian is true + result.BigEndian = true + } + + if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { + return err + } + + if pfBoolByte != 0 { + // True Color is true. So we also have to read all the color max & shifts. + result.TrueColor = true + + if err := binary.Read(brPF, binary.BigEndian, &result.RedMax); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &result.GreenMax); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &result.BlueMax); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &result.RedShift); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &result.GreenShift); err != nil { + return err + } + + if err := binary.Read(brPF, binary.BigEndian, &result.BlueShift); err != nil { + return err + } + } + + return nil +} + +func writePixelFormat(format *common.PixelFormat) ([]byte, error) { + var buf bytes.Buffer + + // Byte 1 + if err := binary.Write(&buf, binary.BigEndian, format.BPP); err != nil { + return nil, err + } + + // Byte 2 + if err := binary.Write(&buf, binary.BigEndian, format.Depth); err != nil { + return nil, 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 nil, err + } + + if format.TrueColor { + boolByte = 1 + } else { + boolByte = 0 + } + + // Byte 4 (TrueColor) + if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil { + return nil, 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 nil, err + } + + if err := binary.Write(&buf, binary.BigEndian, format.GreenMax); err != nil { + return nil, err + } + + if err := binary.Write(&buf, binary.BigEndian, format.BlueMax); err != nil { + return nil, err + } + + if err := binary.Write(&buf, binary.BigEndian, format.RedShift); err != nil { + return nil, err + } + + if err := binary.Write(&buf, binary.BigEndian, format.GreenShift); err != nil { + return nil, err + } + + if err := binary.Write(&buf, binary.BigEndian, format.BlueShift); err != nil { + return nil, err + } + } + + return buf.Bytes()[0:16], nil +} diff --git a/vnc/pointer.go b/client/pointer.go similarity index 89% rename from vnc/pointer.go rename to client/pointer.go index 80f3f13..d9531af 100644 --- a/vnc/pointer.go +++ b/client/pointer.go @@ -1,16 +1,16 @@ -package vnc - -// ButtonMask represents a mask of pointer presses/releases. -type ButtonMask uint8 - -// All available button mask components. -const ( - ButtonLeft ButtonMask = 1 << iota - ButtonMiddle - ButtonRight - Button4 - Button5 - Button6 - Button7 - Button8 -) +package client + +// ButtonMask represents a mask of pointer presses/releases. +type ButtonMask uint8 + +// All available button mask components. +const ( + ButtonLeft ButtonMask = 1 << iota + ButtonMiddle + ButtonRight + Button4 + Button5 + Button6 + Button7 + Button8 +) diff --git a/vnc/server-messages.go b/client/server-messages.go similarity index 99% rename from vnc/server-messages.go rename to client/server-messages.go index f5cddd6..a1cd60a 100644 --- a/vnc/server-messages.go +++ b/client/server-messages.go @@ -1,4 +1,4 @@ -package vnc +package client import ( "encoding/binary" diff --git a/common/client-message.go b/common/client-message.go index 89a7b99..f820b7b 100644 --- a/common/client-message.go +++ b/common/client-message.go @@ -1,9 +1,6 @@ package common -import ( - "io" - "net" -) +import "io" type ClientMessageType uint8 @@ -31,8 +28,8 @@ type Color struct { type ColorMap [256]Color type Conn interface { - io.ReadWriteCloser - Conn() net.Conn + io.ReadWriter + Conn() io.ReadWriter Protocol() string PixelFormat() *PixelFormat SetPixelFormat(*PixelFormat) error @@ -46,7 +43,7 @@ type Conn interface { SetHeight(uint16) DesktopName() string SetDesktopName(string) - Flush() error + //Flush() error SetProtoVersion(string) } diff --git a/main.go b/main.go index ab98b4c..ef10d3b 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,7 @@ import ( "time" "vncproxy/common" "vncproxy/encodings" - "vncproxy/vnc" + "vncproxy/client" ) func main() { @@ -17,12 +17,12 @@ func main() { if err != nil { fmt.Printf("error connecting to vnc server: %s", err) } - var noauth vnc.ClientAuthNone - authArr := []vnc.ClientAuth{&vnc.PasswordAuth{Password: "Ch_#!T@8"}, &noauth} + var noauth client.ClientAuthNone + authArr := []client.ClientAuth{&client.PasswordAuth{Password: "Ch_#!T@8"}, &noauth} vncSrvMessagesChan := make(chan common.ServerMessage) - clientConn, err := vnc.Client(nc, - &vnc.ClientConfig{ + clientConn, err := client.Client(nc, + &client.ClientConfig{ Auth: authArr, ServerMessageCh: vncSrvMessagesChan, Exclusive: true, diff --git a/server/client-messages.go b/server/client-messages.go index c30a414..331835b 100644 --- a/server/client-messages.go +++ b/server/client-messages.go @@ -39,7 +39,7 @@ func (msg *SetPixelFormat) Write(c common.Conn) error { c.SetColorMap(&common.ColorMap{}) } - return c.Flush() + return nil } func (*SetPixelFormat) Read(c common.Conn) (common.ClientMessage, error) { @@ -103,7 +103,7 @@ func (msg *SetEncodings) Write(c common.Conn) error { return err } } - return c.Flush() + return nil } // FramebufferUpdateRequest holds the wire format message. @@ -132,7 +132,7 @@ func (msg *FramebufferUpdateRequest) Write(c common.Conn) error { if err := binary.Write(c, binary.BigEndian, msg); err != nil { return err } - return c.Flush() + return nil } // KeyEvent holds the wire format message. @@ -161,7 +161,7 @@ func (msg *KeyEvent) Write(c common.Conn) error { if err := binary.Write(c, binary.BigEndian, msg); err != nil { return err } - return c.Flush() + return nil } // PointerEventMessage holds the wire format message. @@ -189,7 +189,7 @@ func (msg *PointerEvent) Write(c common.Conn) error { if err := binary.Write(c, binary.BigEndian, msg); err != nil { return err } - return c.Flush() + return nil } // ClientCutText holds the wire format message, sans the text field. @@ -243,5 +243,5 @@ func (msg *ClientCutText) Write(c common.Conn) error { return err } - return c.Flush() + return nil } diff --git a/server/debug.test b/server/debug.test index 1404cd8..cb917cc 100644 Binary files a/server/debug.test and b/server/debug.test differ diff --git a/server/handlers.go b/server/handlers.go index cf70fb6..0423cb4 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -7,20 +7,6 @@ import ( "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 ( @@ -47,45 +33,14 @@ func ParseProtoVersion(pv []byte) (uint, uint, error) { 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 := c.Flush(); err != nil { + // return err + // } if err := binary.Read(c, binary.BigEndian, &version); err != nil { return err } @@ -111,58 +66,6 @@ func ServerVersionHandler(cfg *ServerConfig, c *ServerConn) error { 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 @@ -174,9 +77,9 @@ func ServerSecurityHandler(cfg *ServerConfig, c *ServerConn) error { } } - if err := c.Flush(); 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 { @@ -202,9 +105,9 @@ func ServerSecurityHandler(cfg *ServerConfig, c *ServerConn) error { if err := binary.Write(c, binary.BigEndian, authCode); err != nil { return err } - if err := c.Flush(); 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 { @@ -213,44 +116,15 @@ func ServerSecurityHandler(cfg *ServerConfig, c *ServerConn) error { if err := binary.Write(c, binary.BigEndian, []byte(authErr.Error())); err != nil { return err } - if err := c.Flush(); 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(), @@ -293,7 +167,7 @@ func ServerServerInitHandler(cfg *ServerConfig, c *ServerConn) error { //} //tightInit.WriteTo(c) - return c.Flush() + return nil } const ( @@ -465,19 +339,6 @@ func (t *TightCapability) ReadFrom(r io.Reader) error { 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 { diff --git a/server/security.go b/server/security.go index 6248115..6655910 100644 --- a/server/security.go +++ b/server/security.go @@ -1,333 +1,335 @@ -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 -// } +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 { + pass string +} + +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 := auth.pass + 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 +// } diff --git a/server/server-conn.go b/server/server-conn.go index 6a3fda1..829c0e7 100644 --- a/server/server-conn.go +++ b/server/server-conn.go @@ -1,17 +1,16 @@ package server import ( - "bufio" - "net" + "io" "sync" "vncproxy/common" ) type ServerConn struct { - c net.Conn - cfg *ServerConfig - br *bufio.Reader - bw *bufio.Writer + c io.ReadWriter + 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 @@ -41,11 +40,11 @@ type ServerConn struct { quit chan struct{} } -func (c *ServerConn) UnreadByte() error { - return c.br.UnreadByte() -} +// func (c *ServerConn) UnreadByte() error { +// return c.br.UnreadByte() +// } -func (c *ServerConn) Conn() net.Conn { +func (c *ServerConn) Conn() io.ReadWriter { return c.c } @@ -66,14 +65,14 @@ 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) Flush() error { +// // c.m.Lock() +// // defer c.m.Unlock() +// return c.bw.Flush() +// } func (c *ServerConn) Close() error { - return c.c.Close() + return c.c.(io.ReadWriteCloser).Close() } /* @@ -86,13 +85,13 @@ func (c *ServerConn) Output() chan *ClientMessage { } */ func (c *ServerConn) Read(buf []byte) (int, error) { - return c.br.Read(buf) + return c.c.Read(buf) } func (c *ServerConn) Write(buf []byte) (int, error) { // c.m.Lock() // defer c.m.Unlock() - return c.bw.Write(buf) + return c.c.Write(buf) } func (c *ServerConn) ColorMap() *common.ColorMap { diff --git a/server/server.go b/server/server.go index d7794b3..bf0d617 100644 --- a/server/server.go +++ b/server/server.go @@ -1,12 +1,12 @@ package server import ( - "bufio" "context" "encoding/binary" "fmt" + "io" + "log" "net" - "sync" "vncproxy/common" ) @@ -71,7 +71,7 @@ type ServerConfig struct { Width uint16 } -func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) { +func newServerConn(c io.ReadWriter, cfg *ServerConfig) (*ServerConn, error) { if cfg.ClientMessageCh == nil { return nil, fmt.Errorf("ClientMessageCh nil") } @@ -81,9 +81,9 @@ func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) { } return &ServerConn{ - c: c, - br: bufio.NewReader(c), - bw: bufio.NewWriter(c), + c: c, + //br: bufio.NewReader(c), + //bw: bufio.NewWriter(c), cfg: cfg, quit: make(chan struct{}), encodings: cfg.Encodings, @@ -92,275 +92,137 @@ func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) { fbHeight: cfg.Height, }, nil } +func wsHandlerFunc(ws io.ReadWriter, cfg *ServerConfig) { + // header := ws.Request().Header + // url := ws.Request().URL + // //stam := header.Get("Origin") + // fmt.Printf("header: %v\nurl: %v\n", header, url) + // io.Copy(ws, ws) -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() + err := attachNewServerConn(ws, cfg) + if err != nil { + log.Fatalf("Error attaching new connection. %v", err) } } -func (c *ServerConn) Handle() error { - //var err error - var wg sync.WaitGroup +func WsServe(url string, ctx context.Context, cfg *ServerConfig) error { + //server := WsServer1{cfg} + server := WsServer{cfg} + server.Listen(url, WsHandler(wsHandlerFunc)) + return nil +} - defer c.Close() +func TcpServe(url string, ctx context.Context, cfg *ServerConfig) error { + ln, err := net.Listen("tcp", ":5903") + if err != nil { + log.Fatalf("Error listen. %v", err) + } + for { + c, err := ln.Accept() + if err != nil { + return err + } + go attachNewServerConn(c, cfg) + // if err != nil { + // return err + // } + } + return nil +} + +func attachNewServerConn(c io.ReadWriter, cfg *ServerConfig) error { + + conn, err := newServerConn(c, cfg) + if err != nil { + return err + } + + if err := ServerVersionHandler(cfg, conn); err != nil { + fmt.Errorf("err: %v\n", err) + conn.Close() + return err + } + + if err := ServerSecurityHandler(cfg, conn); err != nil { + conn.Close() + return err + } + + if err := ServerClientInitHandler(cfg, conn); err != nil { + conn.Close() + return err + } + + if err := ServerServerInitHandler(cfg, conn); err != nil { + conn.Close() + return err + } + + //go + conn.handle() + + return nil +} + +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) + //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 - } - } - }() + // 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: + // c.Close() + // 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 + //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 { + fmt.Printf("Error: %v\n", err) + 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 + //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() -// } diff --git a/server/server_test.go b/server/server_test.go index fb7adef..5cc66da 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -3,24 +3,19 @@ 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{}}, + SecurityHandlers: []SecurityHandler{&ServerAuthVNC{"Ch_#!T@8"}}, Encodings: []common.Encoding{&encodings.RawEncoding{}, &encodings.TightEncoding{}, &encodings.CopyRectEncoding{}}, PixelFormat: common.NewPixelFormat(32), ClientMessageCh: chServer, @@ -29,10 +24,10 @@ func TestServer(t *testing.T) { DesktopName: []byte("workDesk"), Height: uint16(768), Width: uint16(1024), - } - go Serve(context.Background(), ln, cfg) - + url := "http://localhost:8091/" + go WsServe(url, context.Background(), cfg) + go TcpServe(":5903", context.Background(), cfg) // Process messages coming in on the ClientMessage channel. for { msg := <-chClient diff --git a/server/ws-server-go.go b/server/ws-server-go.go new file mode 100644 index 0000000..5cc1172 --- /dev/null +++ b/server/ws-server-go.go @@ -0,0 +1,43 @@ +package server + +import ( + "fmt" + "io" + "net/http" + "net/url" + + "golang.org/x/net/websocket" +) + +type WsServer struct { + cfg *ServerConfig +} + +type WsHandler func(io.ReadWriter, *ServerConfig) + +// This example demonstrates a trivial echo server. +func (wsServer *WsServer) Listen(urlStr string, handlerFunc WsHandler) { + //http.Handle("/", websocket.Handler(EchoHandler)) + if urlStr == "" { + urlStr = "/" + } + url, err := url.Parse(urlStr) + if err != nil { + fmt.Println("error while parsing url: ", err) + } + + http.Handle(url.Path, websocket.Handler(func(ws *websocket.Conn) { + // header := ws.Request().Header + // url := ws.Request().URL + // //stam := header.Get("Origin") + // fmt.Printf("header: %v\nurl: %v\n", header, url) + // io.Copy(ws, ws) + ws.PayloadType = websocket.BinaryFrame + handlerFunc(ws, wsServer.cfg) + })) + + err = http.ListenAndServe(url.Host, nil) + if err != nil { + panic("ListenAndServe: " + err.Error()) + } +} diff --git a/server/ws-server-gorilla.go b/server/ws-server-gorilla.go new file mode 100644 index 0000000..6536b0b --- /dev/null +++ b/server/ws-server-gorilla.go @@ -0,0 +1,104 @@ +package server + +import ( + "fmt" + "io" + "log" + "net/http" + "net/url" + + "bytes" + + "github.com/gorilla/websocket" +) + +type WsServer1 struct { + cfg *ServerConfig +} + +type WsHandler1 func(io.ReadWriter, *ServerConfig) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }} + +type WsConnection struct { + Reader WsReader + Writer WsWriter +} + +func NewWsConnection(c *websocket.Conn) *WsConnection { + return &WsConnection{ + WsReader{}, + WsWriter{c}, + } +} + +type WsWriter struct { + conn *websocket.Conn +} + +type WsReader struct { + Buff bytes.Buffer +} + +func (wr WsReader) Read(p []byte) (n int, err error) { + return wr.Buff.Read(p) +} + +func (wr WsWriter) Write(p []byte) (int, error) { + err := wr.conn.WriteMessage(websocket.BinaryMessage, p) + return len(p), err +} + +func handleConnection(w http.ResponseWriter, r *http.Request) { + log.Print("got connection:", r.URL) + c, err := upgrader.Upgrade(w, r, nil) + + if err != nil { + log.Print("upgrade:", err) + return + } + defer c.Close() + + myConn := NewWsConnection(c) + + for { + mt, message, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + break + } + if mt == websocket.BinaryMessage { + myConn.Reader.Buff.Write(message) + } + log.Printf("recv: %s", message) + // err = c.WriteMessage(mt, message) + // if err != nil { + // log.Println("write:", err) + // break + // } + } +} + +// This example demonstrates a trivial echo server. +func (wsServer *WsServer1) Listen(urlStr string, handlerFunc WsHandler) { + //http.Handle("/", websocket.Handler(EchoHandler)) + if urlStr == "" { + urlStr = "/" + } + url, err := url.Parse(urlStr) + if err != nil { + fmt.Println("error while parsing url: ", err) + } + + http.HandleFunc(url.Path, handleConnection) + + err = http.ListenAndServe(url.Host, nil) + if err != nil { + panic("ListenAndServe: " + err.Error()) + } +} diff --git a/server/ws_test.go b/server/ws_test.go new file mode 100644 index 0000000..02adafc --- /dev/null +++ b/server/ws_test.go @@ -0,0 +1,33 @@ +package server + +// import ( +// "fmt" +// "io" +// "net/http" +// "testing" + +// "golang.org/x/net/websocket" +// ) + +// func TestWsServer(t *testing.T) { +// server := WsServer{} +// server.Listen(":8090") +// } + +// // Echo the data received on the WebSocket. +// func EchoHandler(ws *websocket.Conn) { +// header := ws.Request().Header +// url := ws.Request().URL +// //stam := header.Get("Origin") +// fmt.Printf("header: %v\nurl: %v\n", header, url) +// io.Copy(ws, ws) +// } + +// // This example demonstrates a trivial echo server. +// func TestGoWsServer(t *testing.T) { +// http.Handle("/", websocket.Handler(EchoHandler)) +// err := http.ListenAndServe(":11111", nil) +// if err != nil { +// panic("ListenAndServe: " + err.Error()) +// } +// } diff --git a/listeners/multiListener.go b/tee-listeners/multiListener.go similarity index 100% rename from listeners/multiListener.go rename to tee-listeners/multiListener.go diff --git a/listeners/pass-to.go b/tee-listeners/pass-to.go similarity index 100% rename from listeners/pass-to.go rename to tee-listeners/pass-to.go diff --git a/listeners/recorder.go b/tee-listeners/recorder.go similarity index 100% rename from listeners/recorder.go rename to tee-listeners/recorder.go diff --git a/vncproxy.iml b/vncproxy.iml new file mode 100644 index 0000000..f65c0ac --- /dev/null +++ b/vncproxy.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file