Addded README
Code cleanup
This commit is contained in:
23
README.md
Normal file
23
README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# PyVNCs
|
||||
|
||||
Simple command line multiplatform python VNC Server.
|
||||
|
||||
This is a simple command line VNC server, aimed to quick remote support situations.
|
||||
|
||||
This VNC Server is proven to work on:
|
||||
- Linux (Xorg, Wayland not supported so far)
|
||||
- Mac OS
|
||||
- Windows (7 and onwards)
|
||||
|
||||
Supported encodings:
|
||||
- raw
|
||||
- zlib
|
||||
|
||||
TODO:
|
||||
- Add support for more (efficient) encodings
|
||||
- VEnCrypt support (WIP)
|
||||
- Add support for uPnP (for incomming connections on supported nat gateways)
|
||||
|
||||
FAQ:
|
||||
Q: Why a VNC server on python?
|
||||
A: Because python is fun!
|
||||
88
lib/auth/vencrypt.py
Normal file
88
lib/auth/vencrypt.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from lib import log
|
||||
from time import sleep
|
||||
import ssl
|
||||
import select
|
||||
from struct import *
|
||||
|
||||
class VeNCrypt():
|
||||
|
||||
subtypes = [
|
||||
256, # Plain
|
||||
#258, # TLSVnc # FIXME: not yet implemented
|
||||
#259, # TLSPlain # FIXME: not yet implemented
|
||||
]
|
||||
|
||||
def __init__(self, sock):
|
||||
self.getbuff = lambda _: None
|
||||
self.sock = sock
|
||||
self.client_subtype = None
|
||||
self.pem_file = None
|
||||
log.debug(__name__, "initialized")
|
||||
|
||||
# send version
|
||||
version = b'\x00\x02' # 0.2
|
||||
sock.send(version)
|
||||
data = sock.recv(2)
|
||||
if data != version:
|
||||
sock.send(b'\x01')
|
||||
sock.close()
|
||||
raise Exception("unknown vencrypt version")
|
||||
|
||||
sock.send(b'\x00')
|
||||
|
||||
def send_subtypes(self):
|
||||
# send subtypes
|
||||
data = pack('!B', len(self.subtypes))
|
||||
for i in self.subtypes:
|
||||
data += pack('!I', i)
|
||||
log.debug(__name__, "subtype", i)
|
||||
|
||||
self.sock.send(data)
|
||||
|
||||
# get client choosen subtype
|
||||
data = self.sock.recv(4)
|
||||
(data,) = unpack('!I', data)
|
||||
log.debug("client subtype", data)
|
||||
self.client_subtype = data
|
||||
|
||||
def auth_plain(self, userlist={}):
|
||||
data = self.sock.recv(8)
|
||||
user_length, pass_length = unpack('!II', data)
|
||||
username = self.sock.recv(user_length).decode()
|
||||
password = self.sock.recv(pass_length).decode()
|
||||
#log.debug("user", username, password)
|
||||
|
||||
if userlist.get(username) == password:
|
||||
self.sock.send(pack("!I", 0))
|
||||
log.debug(__name__, "Auth OK")
|
||||
return True
|
||||
else:
|
||||
log.debug(__name__, "Invalid auth")
|
||||
sleep(3)
|
||||
self.sock.send(pack("!I", 1))
|
||||
return False
|
||||
|
||||
def auth_tls_plain(self, userlist={}):
|
||||
#TODO: implement TLS plain
|
||||
log.debug(__name__, 'Using TLSPlain')
|
||||
|
||||
self.sock.sendall(pack("!I", 1)) # send ACK
|
||||
|
||||
#data = self.getbuff(30)
|
||||
#print("data", data)
|
||||
|
||||
|
||||
#sslctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
sslctx = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_SERVER)
|
||||
sslctx.protocol = ssl.PROTOCOL_TLS
|
||||
#sslctx.load_cert_chain(certfile=self.pem_file, keyfile=self.pem_file)
|
||||
# this is quite insecure...
|
||||
sslctx.set_ciphers(":aNULL:kDHE:kEDH:ADH:DH:kECDHE:kEECDH:AECDH:ECDH")
|
||||
|
||||
self.sock.settimeout(30)
|
||||
self.sock = sslctx.wrap_socket(self.sock, server_side=True)
|
||||
self.sock.settimeout(None)
|
||||
|
||||
ret = self.auth_plain(userlist=userlist)
|
||||
return ret
|
||||
|
||||
45
lib/auth/vnc_auth.py
Normal file
45
lib/auth/vnc_auth.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from time import sleep
|
||||
from struct import *
|
||||
from pyDes import *
|
||||
import os
|
||||
from lib import log
|
||||
|
||||
class VNCAuth():
|
||||
|
||||
def __init__(self):
|
||||
self.getbuff = lambda _: None
|
||||
|
||||
def _mirrorBits(self, key):
|
||||
newkey = []
|
||||
for ki in range(len(key)):
|
||||
bsrc = key[ki]
|
||||
btgt = 0
|
||||
for i in range(8):
|
||||
if ord(bsrc) & (1 << i):
|
||||
btgt = btgt | (1 << 7-i)
|
||||
newkey.append(btgt)
|
||||
|
||||
return newkey
|
||||
|
||||
def auth(self, sock, password):
|
||||
# el cliente encripta el challenge con la contraseña ingresada como key
|
||||
pw = (password + '\0' * 8)[:8]
|
||||
challenge = os.urandom(16) # challenge
|
||||
sock.send(challenge) # send challenge
|
||||
# obtener desde el cliente el dato encritado
|
||||
data = self.getbuff(30)
|
||||
# la encriptacion de challenge, con pw como key debe dar data
|
||||
|
||||
k = des(self._mirrorBits(pw))
|
||||
crypted = k.encrypt(challenge)
|
||||
|
||||
if data == crypted:
|
||||
# Handshake successful
|
||||
sock.send(pack("!I", 0))
|
||||
log.debug(__name__, "Auth OK")
|
||||
return True
|
||||
else:
|
||||
log.debug(__name__, "Invalid auth")
|
||||
sleep(3)
|
||||
sock.send(pack("!I", 1))
|
||||
return False
|
||||
30
lib/clipboardctrl.py
Normal file
30
lib/clipboardctrl.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from struct import *
|
||||
|
||||
class ClipboardController():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def client_cut_text(self, sock):
|
||||
"""
|
||||
The client has new ISO 8859-1 (Latin-1) text in its cut buffer.
|
||||
Ends of lines are represented by the linefeed / newline character (value 10) alone. No carriage-return (value 13) is needed.
|
||||
|
||||
No. of bytes Type [Value] Description
|
||||
1 U8 6 message-type
|
||||
3 padding
|
||||
4 U32 length
|
||||
length U8 array text
|
||||
"""
|
||||
|
||||
# read padding
|
||||
_ = sock.recv(3)
|
||||
|
||||
# read length
|
||||
length = sock.recv(4)
|
||||
(length, ) = unpack('!I', length)
|
||||
|
||||
# read text
|
||||
text = sock.recv(length)
|
||||
|
||||
return text
|
||||
@@ -66,3 +66,9 @@ class proc:
|
||||
def waitproc(self):
|
||||
while psutil.pid_exists(self.pid):
|
||||
time.sleep(.25)
|
||||
|
||||
def reshape(a, cols):
|
||||
|
||||
for i in range(0, int(len(a)/cols), cols):
|
||||
print(i)
|
||||
print(a[i:i+cols])
|
||||
|
||||
39
lib/log.py
39
lib/log.py
@@ -15,14 +15,41 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG, format='[%(threadName)s] %(message)s')
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s: %(message)s')
|
||||
logger = logging.getLogger('pyvncs')
|
||||
|
||||
def _log(*args, logtype='debug'):
|
||||
|
||||
func = inspect.stack()[2][3]
|
||||
if func[0] != '<':
|
||||
func = "%s():" % func
|
||||
|
||||
_str = func
|
||||
|
||||
def debug(*args):
|
||||
str = ""
|
||||
for s in args:
|
||||
str = "%s %s" % (str, s)
|
||||
str = str.strip()
|
||||
logger.debug(str)
|
||||
_str = "%s %s" % (_str, s)
|
||||
_str = _str.strip()
|
||||
f = getattr(logger, logtype)
|
||||
#logger.debug(str)
|
||||
f(_str)
|
||||
|
||||
def __getattr__(name):
|
||||
|
||||
def method(*args):
|
||||
_str = ''
|
||||
if args:
|
||||
for s in args:
|
||||
_str = "%s %s" % (_str, s)
|
||||
_str = _str.strip()
|
||||
|
||||
_log(_str, logtype=name)
|
||||
|
||||
return method
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
109
lib/rfb_bitmap.py
Normal file
109
lib/rfb_bitmap.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import numpy as np
|
||||
from PIL import Image, ImageChops, ImageDraw, ImagePalette
|
||||
from lib import bgr233_palette
|
||||
|
||||
__all__ = ['RfbBitmap']
|
||||
|
||||
class RfbBitmap():
|
||||
|
||||
def __init__(self):
|
||||
self.bpp = None
|
||||
self.depth = None
|
||||
self.truecolor = None
|
||||
self.primaryOrder = 'rgb'
|
||||
self.dither = False
|
||||
self.red_shift = None
|
||||
self.green_shift = None
|
||||
self.blue_shift = None
|
||||
|
||||
def __quantizetopalette(self, silf, palette, dither=False):
|
||||
"""Converts an RGB or L mode image to use a given P image's palette."""
|
||||
silf.load()
|
||||
|
||||
# use palette from reference image
|
||||
palette.load()
|
||||
if palette.mode != "P":
|
||||
raise ValueError("bad mode for palette image")
|
||||
if silf.mode != "RGB" and silf.mode != "L":
|
||||
raise ValueError(
|
||||
"only RGB or L mode images can be quantized to a palette"
|
||||
)
|
||||
im = silf.im.convert("P", 1 if dither else 0, palette.im)
|
||||
# the 0 above means turn OFF dithering
|
||||
|
||||
# Later versions of Pillow (4.x) rename _makeself to _new
|
||||
try:
|
||||
return silf._new(im)
|
||||
except AttributeError:
|
||||
return silf._makeself(im)
|
||||
|
||||
|
||||
def get_bitmap(self, rectangle):
|
||||
if self.bpp == 32:
|
||||
redBits = 8
|
||||
greenBits = 8
|
||||
blueBits = 8
|
||||
|
||||
# image array
|
||||
a = np.asarray(rectangle).copy()
|
||||
|
||||
redMask = ((1 << redBits) - 1) << self.red_shift
|
||||
greenMask = ((1 << greenBits) - 1) << self.green_shift
|
||||
blueMask = ((1 << blueBits) - 1) << self.blue_shift
|
||||
a[..., 0] = ( a[..., 0] ) & redMask >> self.red_shift
|
||||
a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift
|
||||
a[..., 2] = ( a[..., 2] ) & blueMask >> self.blue_shift
|
||||
|
||||
image = Image.fromarray(a)
|
||||
if self.primaryOrder == "rgb":
|
||||
(b, g, r) = image.split()
|
||||
image = Image.merge("RGB", (r, g, b))
|
||||
del b,g,r
|
||||
image = image.convert("RGBX")
|
||||
return image
|
||||
|
||||
elif self.bpp == 16: #BGR565
|
||||
greenBits = 5
|
||||
blueBits = 6
|
||||
redBits = 5
|
||||
image = rectangle
|
||||
|
||||
if self.primaryOrder == "bgr": # FIXME: does not work
|
||||
(b, g, r) = image.split()
|
||||
image = Image.merge("RGB", (r, g, b))
|
||||
|
||||
if self.depth == 16:
|
||||
image = image.convert('BGR;16')
|
||||
if self.depth == 15:
|
||||
image = image.convert('BGR;15')
|
||||
|
||||
return image
|
||||
|
||||
elif self.bpp == 8: #bgr233
|
||||
redBits = 3
|
||||
greenBits = 3
|
||||
blueBits = 2
|
||||
image = rectangle
|
||||
|
||||
palette = bgr233_palette.palette
|
||||
if self.primaryOrder == "rgb":
|
||||
#(b, g, r) = image.split()
|
||||
#image = Image.merge("RGB", (r, g, b))
|
||||
|
||||
palette = np.reshape(palette, (-3,3))
|
||||
palette[:,[0, 2]] = palette[:,[2, 0]]
|
||||
palette = palette.flatten()
|
||||
palette = list(palette)
|
||||
|
||||
p = Image.new('P',(16,16))
|
||||
p.putpalette(palette)
|
||||
|
||||
image = self.__quantizetopalette(image, p, dither=self.dither)
|
||||
|
||||
#image = image.convert('RGB', colors=4).quantize(palette=p)
|
||||
#log.debug(image)
|
||||
return image
|
||||
|
||||
else:
|
||||
# unsupported BPP
|
||||
return None
|
||||
236
pyvncs/server.py
236
pyvncs/server.py
@@ -30,94 +30,52 @@ import numpy as np
|
||||
|
||||
from lib import mousectrl
|
||||
from lib import kbdctrl
|
||||
from lib import clipboardctrl
|
||||
from lib.imagegrab import ImageGrab
|
||||
from lib.rfb_bitmap import RfbBitmap
|
||||
from lib import log
|
||||
from lib import bgr233_palette
|
||||
|
||||
# encodings support
|
||||
import lib.encodings as encs
|
||||
from lib.encodings.common import ENCODINGS
|
||||
|
||||
def hexdump(data):
|
||||
str = ""
|
||||
for d in data:
|
||||
str += hex(d)
|
||||
str += "(%s) " % d
|
||||
return str
|
||||
|
||||
def quantizetopalette(silf, palette, dither=False):
|
||||
"""Converts an RGB or L mode image to use a given P image's palette."""
|
||||
|
||||
silf.load()
|
||||
|
||||
# use palette from reference image
|
||||
palette.load()
|
||||
if palette.mode != "P":
|
||||
raise ValueError("bad mode for palette image")
|
||||
if silf.mode != "RGB" and silf.mode != "L":
|
||||
raise ValueError(
|
||||
"only RGB or L mode images can be quantized to a palette"
|
||||
)
|
||||
im = silf.im.convert("P", 1 if dither else 0, palette.im)
|
||||
# the 0 above means turn OFF dithering
|
||||
|
||||
# Later versions of Pillow (4.x) rename _makeself to _new
|
||||
try:
|
||||
return silf._new(im)
|
||||
except AttributeError:
|
||||
return silf._makeself(im)
|
||||
# auth support
|
||||
from lib.auth.vnc_auth import VNCAuth
|
||||
from lib.auth.vencrypt import VeNCrypt
|
||||
|
||||
class VncServer():
|
||||
|
||||
class CONFIG:
|
||||
_8bitdither = False
|
||||
class RFB_SECTYPES:
|
||||
vncauth = 2 # plain VNC auth
|
||||
vencrypt = 19 # VeNCrypt
|
||||
unix = 129 # Unix Login Authentication
|
||||
|
||||
encoding_object = None
|
||||
|
||||
def __init__(self, socket, password):
|
||||
def __init__(self, socket, password=None, auth_type=None, pem_file='', vnc_config = None):
|
||||
self.RFB_VERSION = '003.008'
|
||||
self.RFB_SECTYPES = [
|
||||
2, # VNC auth
|
||||
19 # VeNCrypt
|
||||
]
|
||||
self.initmsg = ("RFB %s\n" % self.RFB_VERSION)
|
||||
self.socket = socket
|
||||
self.framebuffer = None
|
||||
self.password = password
|
||||
self.sectypes = self.RFB_SECTYPES
|
||||
self.cursor_support = False
|
||||
self.auth_type = auth_type
|
||||
self.pem_file = pem_file
|
||||
self.vnc_config = vnc_config
|
||||
|
||||
log.debug("Configured auth type:", self.auth_type)
|
||||
|
||||
|
||||
def __del__(self):
|
||||
log.debug("VncServer died")
|
||||
|
||||
def encrypt(self, key, data):
|
||||
k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
|
||||
d = k.encrypt(data)
|
||||
return d
|
||||
|
||||
def decrypt(self, challenge, data):
|
||||
k = des(challenge, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
|
||||
return k.decrypt(data)
|
||||
|
||||
def mirrorBits(self, key):
|
||||
newkey = []
|
||||
for ki in range(len(key)):
|
||||
bsrc = key[ki]
|
||||
btgt = 0
|
||||
for i in range(8):
|
||||
if ord(bsrc) & (1 << i):
|
||||
btgt = btgt | (1 << 7-i)
|
||||
newkey.append(btgt)
|
||||
|
||||
return newkey
|
||||
|
||||
def sendmessage(self, message):
|
||||
''' sends a RFB message, usually an error message '''
|
||||
sock = self.socket
|
||||
message = bytes(message, 'iso8859-1')
|
||||
# 4 bytes lenght and string
|
||||
buff = pack("I%ds" % (len(message),), len(message), message)
|
||||
sock.send(message)
|
||||
sock.send(buff)
|
||||
|
||||
def getbuff(self, timeout):
|
||||
sock = self.socket
|
||||
@@ -149,17 +107,27 @@ class VncServer():
|
||||
log.debug("client, server:", client_version, server_version)
|
||||
|
||||
# security types handshake
|
||||
sendbuff = pack("B", len(self.sectypes)) # number of security types
|
||||
sendbuff += pack('%sB' % len(self.sectypes), *self.sectypes) # send available sec types
|
||||
# sectypes = [
|
||||
# self.RFB_SECTYPES.vncauth,
|
||||
# self.RFB_SECTYPES.vencrypt
|
||||
# ]
|
||||
|
||||
sectypes = [
|
||||
self.auth_type
|
||||
]
|
||||
log.debug('sectypes', sectypes)
|
||||
sendbuff = pack("B", len(sectypes)) # number of security types
|
||||
sendbuff += pack('%sB' % len(sectypes), *sectypes) # send available sec types
|
||||
sock.send(sendbuff)
|
||||
|
||||
# get client choosen security type
|
||||
data = self.getbuff(30)
|
||||
try:
|
||||
sectype = unpack("B", data)[0]
|
||||
except:
|
||||
sectype = None
|
||||
|
||||
if sectype not in self.sectypes:
|
||||
if sectype not in sectypes:
|
||||
log.debug("Incompatible security type: %s" % data)
|
||||
sock.send(pack("B", 1)) # failed handshake
|
||||
self.sendmessage("Incompatible security type")
|
||||
@@ -169,28 +137,57 @@ class VncServer():
|
||||
log.debug("sec type data: %s" % data)
|
||||
|
||||
# VNC Auth
|
||||
if sectype == 2:
|
||||
# el cliente encripta el challenge con la contraseña ingresada como key
|
||||
pw = (self.password + '\0' * 8)[:8]
|
||||
challenge = os.urandom(16) # challenge
|
||||
sock.send(challenge) # send challenge
|
||||
# obtener desde el cliente el dato encritado
|
||||
data = self.getbuff(30)
|
||||
# la encriptacion de challenge, con pw como key debe dar data
|
||||
|
||||
k = des(self.mirrorBits(pw))
|
||||
crypted = k.encrypt(challenge)
|
||||
|
||||
if data == crypted:
|
||||
# Handshake successful
|
||||
sock.send(pack("I", 0))
|
||||
log.debug("Auth OK")
|
||||
else:
|
||||
log.debug("Invalid auth")
|
||||
if sectype == self.RFB_SECTYPES.vncauth:
|
||||
auth = VNCAuth()
|
||||
auth.getbuff = self.getbuff
|
||||
if not auth.auth(sock, self.password):
|
||||
msg = "Auth failed."
|
||||
sendbuff = pack("I", len(msg))
|
||||
sendbuff += msg.encode()
|
||||
sock.send(sendbuff)
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
# VeNCrypt
|
||||
elif sectype == self.RFB_SECTYPES.vencrypt:
|
||||
userlist = {}
|
||||
try:
|
||||
userlist[self.password.split(':')[0]] = self.password.split(':')[1]
|
||||
except Exception as ex:
|
||||
log.debug("Unable to parse username:password combination.\n%s" % ex)
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
auth = VeNCrypt(sock)
|
||||
auth.getbuff = self.getbuff
|
||||
auth.send_subtypes()
|
||||
client_subtype = auth.client_subtype
|
||||
|
||||
if client_subtype == 256: # Vencrypt Plain auth
|
||||
if not auth.auth_plain(userlist):
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
if client_subtype == 259: # Vencrypt TLSPlain auth
|
||||
auth.pem_file = self.pem_file
|
||||
auth.socket = self.socket
|
||||
if not auth.auth_tls_plain(userlist):
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
else:
|
||||
# unsupported subtype
|
||||
log.debug("Unsuported client_subtype", client_subtype)
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
#elif sectype == self.RFB_SECTYPES.unix:
|
||||
# log.debug("UNIX!!")
|
||||
|
||||
#unsupported VNC auth type
|
||||
else:
|
||||
log.debug("Unsupported auth type")
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
# get ClientInit
|
||||
@@ -216,7 +213,7 @@ class VncServer():
|
||||
height = size[1]
|
||||
self.height = height
|
||||
bpp = 32 # FIXME: get real bpp
|
||||
depth = 32 # FIXME: get real depth
|
||||
depth = 24 # FIXME: get real depth
|
||||
self.depth = depth
|
||||
self.bpp = bpp
|
||||
bigendian = 0
|
||||
@@ -233,13 +230,14 @@ class VncServer():
|
||||
self.green_shift = green_shift
|
||||
blue_shift = 0
|
||||
self.blue_shift = blue_shift
|
||||
self.rfb_bitmap = RfbBitmap()
|
||||
|
||||
sendbuff = pack("!HH", width, height)
|
||||
sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor)
|
||||
sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift)
|
||||
sendbuff += pack("!xxx") # padding
|
||||
|
||||
desktop_name = "Test VNC"
|
||||
desktop_name = self.vnc_config.win_title
|
||||
desktop_name_len = len(desktop_name)
|
||||
|
||||
sendbuff += pack("!I", desktop_name_len)
|
||||
@@ -261,6 +259,7 @@ class VncServer():
|
||||
|
||||
mousecontroller = mousectrl.MouseController()
|
||||
kbdcontroller = kbdctrl.KeyboardController()
|
||||
clipboardcontroller = clipboardctrl.ClipboardController()
|
||||
|
||||
self.primaryOrder = "rgb"
|
||||
self.encoding = ENCODINGS.raw
|
||||
@@ -358,6 +357,10 @@ class VncServer():
|
||||
mousecontroller.process_event(sock.recv(5, socket.MSG_WAITALL))
|
||||
continue
|
||||
|
||||
if data[0] == 6: # ClientCutText
|
||||
text = clipboardcontroller.client_cut_text(sock)
|
||||
log.debug("ClientCutText:", text)
|
||||
|
||||
else:
|
||||
data2 = sock.recv(4096)
|
||||
log.debug("RAW Server received data:", repr(data[0]) , data+data2)
|
||||
@@ -421,66 +424,17 @@ class VncServer():
|
||||
sock.settimeout(None)
|
||||
|
||||
if self.bpp == 32 or self.bpp == 16 or self.bpp == 8:
|
||||
bitmap = self.rfb_bitmap
|
||||
bitmap.bpp = self.bpp
|
||||
bitmap.depth = self.depth
|
||||
bitmap.dither = self.vnc_config.eightbitdither
|
||||
bitmap.primaryOrder = self.primaryOrder
|
||||
bitmap.truecolor = self.truecolor
|
||||
bitmap.red_shift = self.red_shift
|
||||
bitmap.green_shift = self.green_shift
|
||||
bitmap.blue_shift = self.blue_shift
|
||||
|
||||
if self.bpp == 32:
|
||||
redBits = 8
|
||||
greenBits = 8
|
||||
blueBits = 8
|
||||
|
||||
# image array
|
||||
a = np.asarray(rectangle).copy()
|
||||
|
||||
if self.primaryOrder == "bgr": # bit shifting
|
||||
blueMask = (1 << blueBits) - 1
|
||||
greenMask = ((1 << greenBits) - 1) << self.green_shift
|
||||
redMask = ((1 << redBits) - 1) << self.red_shift
|
||||
|
||||
a[..., 0] = ( a[..., 0] ) & blueMask >> self.blue_shift
|
||||
a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift
|
||||
a[..., 2] = ( a[..., 2] ) & redMask >> self.red_shift
|
||||
|
||||
else: # RGB
|
||||
redMask = ((1 << redBits) - 1) << self.red_shift
|
||||
greenMask = ((1 << greenBits) - 1) << self.green_shift
|
||||
blueMask = ((1 << blueBits) - 1) << self.blue_shift
|
||||
a[..., 0] = ( a[..., 0] ) & redMask >> self.red_shift
|
||||
a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift
|
||||
a[..., 2] = ( a[..., 2] ) & blueMask >> self.blue_shift
|
||||
|
||||
image = Image.fromarray(a)
|
||||
if self.primaryOrder == "rgb":
|
||||
(b, g, r) = image.split()
|
||||
image = Image.merge("RGB", (r, g, b))
|
||||
del b,g,r
|
||||
image = image.convert("RGBX")
|
||||
|
||||
if self.bpp == 16: #BGR565
|
||||
greenBits = 5
|
||||
blueBits = 6
|
||||
redBits = 5
|
||||
|
||||
image = rectangle
|
||||
if self.depth == 16:
|
||||
image = image.convert('BGR;16')
|
||||
if self.depth == 15:
|
||||
image = image.convert('BGR;15')
|
||||
|
||||
elif self.bpp == 8: #bgr233
|
||||
redBits = 3
|
||||
greenBits = 3
|
||||
blueBits = 2
|
||||
|
||||
image = rectangle
|
||||
|
||||
p = Image.new('P',(16,16))
|
||||
p.putpalette(bgr233_palette.palette)
|
||||
|
||||
image = quantizetopalette(image, p, dither=self.CONFIG._8bitdither)
|
||||
|
||||
#image = image.convert('RGB', colors=4).quantize(palette=p)
|
||||
#log.debug(image)
|
||||
|
||||
|
||||
image = bitmap.get_bitmap(rectangle)
|
||||
|
||||
# send image with client defined encoding
|
||||
sendbuff.extend(self.encoding_object.send_image(x, y, w, h, image))
|
||||
|
||||
16
test.py
16
test.py
@@ -1,16 +0,0 @@
|
||||
from lib import common
|
||||
import time
|
||||
|
||||
if __name__ == '__main__':
|
||||
#c = ["/bin/ls", "-alh"]
|
||||
#c = ["/bin/sleep", "5"]
|
||||
c = ["./test.sh"]
|
||||
r = common.proc()
|
||||
r.run(c)
|
||||
print("PID", r.getpid())
|
||||
#print("Waiting...")
|
||||
#r.waitproc()
|
||||
time.sleep(1)
|
||||
r.terminate()
|
||||
del r
|
||||
print("DONE")
|
||||
@@ -7,11 +7,11 @@ from threading import Thread
|
||||
from time import sleep
|
||||
import sys
|
||||
import socket
|
||||
import ssl
|
||||
import signal
|
||||
from lib import log
|
||||
|
||||
_debug = log.debug
|
||||
#_debug = print
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
_debug("Exiting on %s signal..." % signal)
|
||||
@@ -19,79 +19,84 @@ def signal_handler(signal, frame):
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
|
||||
class ControlThread(Thread):
|
||||
def __init__(self, threads):
|
||||
Thread.__init__(self)
|
||||
self.threads = threads
|
||||
self.setDaemon(True)
|
||||
|
||||
def run(self):
|
||||
# elimina los threads muertos
|
||||
while True:
|
||||
sleep(1)
|
||||
for t in threads:
|
||||
if not t.isAlive():
|
||||
_debug("ControlThread removing dead", t)
|
||||
threads.remove(t)
|
||||
|
||||
class ClientThread(Thread):
|
||||
def __init__(self, sock, ip, port):
|
||||
def __init__(self, sock, ip, port, vnc_config):
|
||||
Thread.__init__(self)
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
self.sock = sock
|
||||
self.setDaemon(True)
|
||||
self.vnc_config = vnc_config
|
||||
|
||||
|
||||
def __del__(self):
|
||||
_debug("ClientThread died")
|
||||
|
||||
def run(self):
|
||||
_debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
|
||||
#_debug("Thread", self)
|
||||
server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD)
|
||||
server.CONFIG._8bitdither = CONFIG._8bitdither
|
||||
server = pyvncs.server.VncServer(self.sock,
|
||||
auth_type=self.vnc_config.auth_type,
|
||||
password=self.vnc_config.vnc_password,
|
||||
pem_file=self.vnc_config.pem_file,
|
||||
vnc_config=self.vnc_config
|
||||
)
|
||||
#server.vnc_config.eightbitdither = self.vnc_config.eightbitdither
|
||||
status = server.init()
|
||||
|
||||
if not status:
|
||||
_debug("Error negotiating client init")
|
||||
return False
|
||||
|
||||
server.protocol()
|
||||
|
||||
|
||||
def main(argv):
|
||||
global CONFIG, TCP_IP, TCP_PORT, VNC_PASSWORD, threads, controlthread
|
||||
class CONFIG:
|
||||
_8bitdither = False
|
||||
class vnc_config:
|
||||
pass
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-l", "--listen-address", dest="TCP_IP",
|
||||
parser.add_argument("-l", "--listen-address", dest="listen_addr",
|
||||
help="Listen in this address, default: %s" % ("0.0.0.0"), required=False, default='0.0.0.0')
|
||||
parser.add_argument("-p", "--port", dest="TCP_PORT",
|
||||
parser.add_argument("-p", "--port", dest="listen_port",
|
||||
help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901')
|
||||
parser.add_argument("-P", "--password", help="Sets password", required=True, dest="VNC_PASSWORD")
|
||||
parser.add_argument("-A", "--auth-type",
|
||||
help="Sets VNC authentication type (supported: 2(vnc), 19(vencrypt))",
|
||||
required=False,
|
||||
type=int,
|
||||
default=2,
|
||||
dest="auth_type"
|
||||
)
|
||||
parser.add_argument("-C", "--cert-file",
|
||||
help="SSL PEM file",
|
||||
required=False,
|
||||
type=str,
|
||||
default='',
|
||||
dest='pem_file'
|
||||
)
|
||||
parser.add_argument("-P", "--vncpassword", help="Sets authentication password", required=True, dest="vnc_password")
|
||||
parser.add_argument("-8", "--8bitdither", help="Enable 8 bit dithering", required=False, action='store_true', dest="dither")
|
||||
parser.add_argument("-O", "--output-file", help="Redirects all debug output to file", required=False, dest="OUTFILE")
|
||||
parser.add_argument("-O", "--output-file", help="Redirects all debug output to file", required=False, dest="outfile")
|
||||
parser.add_argument("-t", "--title", help="VNC Window title", required=False, dest="win_title", default="pyvncs")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.OUTFILE is not None:
|
||||
fsock = open(args.OUTFILE, 'w')
|
||||
if args.outfile is not None:
|
||||
try:
|
||||
fsock = open(args.outfile, 'w')
|
||||
except Exception as ex:
|
||||
print("Error:", ex, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
sys.stdout = sys.stderr = fsock
|
||||
|
||||
# Multithreaded Python server
|
||||
TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP
|
||||
TCP_PORT = '5901' if not hasattr(args,"TCP_PORT") else args.TCP_PORT
|
||||
VNC_PASSWORD = args.VNC_PASSWORD
|
||||
CONFIG._8bitdither = args.dither
|
||||
vnc_config.vnc_password = args.vnc_password
|
||||
vnc_config.eightbitdither = args.dither
|
||||
vnc_config.auth_type = args.auth_type
|
||||
vnc_config.pem_file = args.pem_file
|
||||
vnc_config.win_title = args.win_title
|
||||
|
||||
sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sockServer.bind((TCP_IP, TCP_PORT))
|
||||
|
||||
controlthread = ControlThread(threads)
|
||||
controlthread.start()
|
||||
threads.append(controlthread)
|
||||
sockServer.bind((args.listen_addr, args.listen_port))
|
||||
|
||||
_debug("Multithreaded Python server : Waiting for connections from TCP clients...")
|
||||
_debug("Runing on:", sys.platform)
|
||||
@@ -111,21 +116,16 @@ def main(argv):
|
||||
while True:
|
||||
sockServer.listen(4)
|
||||
(conn, (ip,port)) = sockServer.accept()
|
||||
newthread = ClientThread(conn, ip, port)
|
||||
newthread = ClientThread(sock=conn, ip=ip, port=port, vnc_config=vnc_config)
|
||||
newthread.setDaemon(True)
|
||||
newthread.start()
|
||||
threads.append(newthread)
|
||||
#print(threads)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
threads = []
|
||||
main(sys.argv)
|
||||
except KeyboardInterrupt:
|
||||
# quit
|
||||
_debug("Exiting on ctrl+c...")
|
||||
#for t in threads:
|
||||
# _debug("Killing", t)
|
||||
sys.exit()
|
||||
|
||||
Reference in New Issue
Block a user