Addded README

Code cleanup
This commit is contained in:
Matias Fernandez
2019-09-11 22:00:39 -03:00
parent a6327060f9
commit aad1e08f6a
11 changed files with 476 additions and 216 deletions

23
README.md Normal file
View 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
View 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
View 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
View 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

View File

@@ -66,3 +66,9 @@ class proc:
def waitproc(self): def waitproc(self):
while psutil.pid_exists(self.pid): while psutil.pid_exists(self.pid):
time.sleep(.25) time.sleep(.25)
def reshape(a, cols):
for i in range(0, int(len(a)/cols), cols):
print(i)
print(a[i:i+cols])

View File

@@ -15,14 +15,41 @@
# You should have received a copy of the GNU Lesser General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import inspect
import logging 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') 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: for s in args:
str = "%s %s" % (str, s) _str = "%s %s" % (_str, s)
str = str.strip() _str = _str.strip()
logger.debug(str) 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
View 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

View File

@@ -30,94 +30,52 @@ import numpy as np
from lib import mousectrl from lib import mousectrl
from lib import kbdctrl from lib import kbdctrl
from lib import clipboardctrl
from lib.imagegrab import ImageGrab from lib.imagegrab import ImageGrab
from lib.rfb_bitmap import RfbBitmap
from lib import log from lib import log
from lib import bgr233_palette
# encodings support # encodings support
import lib.encodings as encs import lib.encodings as encs
from lib.encodings.common import ENCODINGS from lib.encodings.common import ENCODINGS
def hexdump(data): # auth support
str = "" from lib.auth.vnc_auth import VNCAuth
for d in data: from lib.auth.vencrypt import VeNCrypt
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)
class VncServer(): class VncServer():
class CONFIG: class RFB_SECTYPES:
_8bitdither = False vncauth = 2 # plain VNC auth
vencrypt = 19 # VeNCrypt
unix = 129 # Unix Login Authentication
encoding_object = None 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_VERSION = '003.008'
self.RFB_SECTYPES = [
2, # VNC auth
19 # VeNCrypt
]
self.initmsg = ("RFB %s\n" % self.RFB_VERSION) self.initmsg = ("RFB %s\n" % self.RFB_VERSION)
self.socket = socket self.socket = socket
self.framebuffer = None self.framebuffer = None
self.password = password self.password = password
self.sectypes = self.RFB_SECTYPES
self.cursor_support = False 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): def __del__(self):
log.debug("VncServer died") 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): def sendmessage(self, message):
''' sends a RFB message, usually an error message ''' ''' sends a RFB message, usually an error message '''
sock = self.socket sock = self.socket
message = bytes(message, 'iso8859-1') message = bytes(message, 'iso8859-1')
# 4 bytes lenght and string # 4 bytes lenght and string
buff = pack("I%ds" % (len(message),), len(message), message) buff = pack("I%ds" % (len(message),), len(message), message)
sock.send(message) sock.send(buff)
def getbuff(self, timeout): def getbuff(self, timeout):
sock = self.socket sock = self.socket
@@ -149,17 +107,27 @@ class VncServer():
log.debug("client, server:", client_version, server_version) log.debug("client, server:", client_version, server_version)
# security types handshake # security types handshake
sendbuff = pack("B", len(self.sectypes)) # number of security types # sectypes = [
sendbuff += pack('%sB' % len(self.sectypes), *self.sectypes) # send available sec types # 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) sock.send(sendbuff)
# get client choosen security type
data = self.getbuff(30) data = self.getbuff(30)
try: try:
sectype = unpack("B", data)[0] sectype = unpack("B", data)[0]
except: except:
sectype = None sectype = None
if sectype not in self.sectypes: if sectype not in sectypes:
log.debug("Incompatible security type: %s" % data) log.debug("Incompatible security type: %s" % data)
sock.send(pack("B", 1)) # failed handshake sock.send(pack("B", 1)) # failed handshake
self.sendmessage("Incompatible security type") self.sendmessage("Incompatible security type")
@@ -169,28 +137,57 @@ class VncServer():
log.debug("sec type data: %s" % data) log.debug("sec type data: %s" % data)
# VNC Auth # VNC Auth
if sectype == 2: if sectype == self.RFB_SECTYPES.vncauth:
# el cliente encripta el challenge con la contraseña ingresada como key auth = VNCAuth()
pw = (self.password + '\0' * 8)[:8] auth.getbuff = self.getbuff
challenge = os.urandom(16) # challenge if not auth.auth(sock, self.password):
sock.send(challenge) # send challenge msg = "Auth failed."
# obtener desde el cliente el dato encritado sendbuff = pack("I", len(msg))
data = self.getbuff(30) sendbuff += msg.encode()
# la encriptacion de challenge, con pw como key debe dar data sock.send(sendbuff)
sock.close()
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")
return False 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 #unsupported VNC auth type
else: else:
log.debug("Unsupported auth type")
sock.close()
return False return False
# get ClientInit # get ClientInit
@@ -216,7 +213,7 @@ class VncServer():
height = size[1] height = size[1]
self.height = height self.height = height
bpp = 32 # FIXME: get real bpp bpp = 32 # FIXME: get real bpp
depth = 32 # FIXME: get real depth depth = 24 # FIXME: get real depth
self.depth = depth self.depth = depth
self.bpp = bpp self.bpp = bpp
bigendian = 0 bigendian = 0
@@ -233,13 +230,14 @@ class VncServer():
self.green_shift = green_shift self.green_shift = green_shift
blue_shift = 0 blue_shift = 0
self.blue_shift = blue_shift self.blue_shift = blue_shift
self.rfb_bitmap = RfbBitmap()
sendbuff = pack("!HH", width, height) sendbuff = pack("!HH", width, height)
sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor) sendbuff += pack("!BBBB", bpp, depth, bigendian, truecolor)
sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift) sendbuff += pack("!HHHBBB", red_maximum, green_maximum, blue_maximum, red_shift, green_shift, blue_shift)
sendbuff += pack("!xxx") # padding sendbuff += pack("!xxx") # padding
desktop_name = "Test VNC" desktop_name = self.vnc_config.win_title
desktop_name_len = len(desktop_name) desktop_name_len = len(desktop_name)
sendbuff += pack("!I", desktop_name_len) sendbuff += pack("!I", desktop_name_len)
@@ -261,6 +259,7 @@ class VncServer():
mousecontroller = mousectrl.MouseController() mousecontroller = mousectrl.MouseController()
kbdcontroller = kbdctrl.KeyboardController() kbdcontroller = kbdctrl.KeyboardController()
clipboardcontroller = clipboardctrl.ClipboardController()
self.primaryOrder = "rgb" self.primaryOrder = "rgb"
self.encoding = ENCODINGS.raw self.encoding = ENCODINGS.raw
@@ -358,6 +357,10 @@ class VncServer():
mousecontroller.process_event(sock.recv(5, socket.MSG_WAITALL)) mousecontroller.process_event(sock.recv(5, socket.MSG_WAITALL))
continue continue
if data[0] == 6: # ClientCutText
text = clipboardcontroller.client_cut_text(sock)
log.debug("ClientCutText:", text)
else: else:
data2 = sock.recv(4096) data2 = sock.recv(4096)
log.debug("RAW Server received data:", repr(data[0]) , data+data2) log.debug("RAW Server received data:", repr(data[0]) , data+data2)
@@ -421,66 +424,17 @@ class VncServer():
sock.settimeout(None) sock.settimeout(None)
if self.bpp == 32 or self.bpp == 16 or self.bpp == 8: 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: image = bitmap.get_bitmap(rectangle)
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)
# send image with client defined encoding # send image with client defined encoding
sendbuff.extend(self.encoding_object.send_image(x, y, w, h, image)) sendbuff.extend(self.encoding_object.send_image(x, y, w, h, image))

16
test.py
View File

@@ -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")

View File

@@ -1,6 +0,0 @@
#!/bin/bash
for a in $(seq 1 5); do
echo "$a $$"
sleep 1
done

View File

@@ -7,11 +7,11 @@ from threading import Thread
from time import sleep from time import sleep
import sys import sys
import socket import socket
import ssl
import signal import signal
from lib import log from lib import log
_debug = log.debug _debug = log.debug
#_debug = print
def signal_handler(signal, frame): def signal_handler(signal, frame):
_debug("Exiting on %s signal..." % signal) _debug("Exiting on %s signal..." % signal)
@@ -19,79 +19,84 @@ def signal_handler(signal, frame):
signal.signal(signal.SIGINT, signal_handler) 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): class ClientThread(Thread):
def __init__(self, sock, ip, port): def __init__(self, sock, ip, port, vnc_config):
Thread.__init__(self) Thread.__init__(self)
self.ip = ip self.ip = ip
self.port = port self.port = port
self.sock = sock self.sock = sock
self.setDaemon(True) self.setDaemon(True)
self.vnc_config = vnc_config
def __del__(self): def __del__(self):
_debug("ClientThread died") _debug("ClientThread died")
def run(self): def run(self):
_debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) _debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
#_debug("Thread", self) server = pyvncs.server.VncServer(self.sock,
server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD) auth_type=self.vnc_config.auth_type,
server.CONFIG._8bitdither = CONFIG._8bitdither 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() status = server.init()
if not status: if not status:
_debug("Error negotiating client init") _debug("Error negotiating client init")
return False return False
server.protocol() server.protocol()
def main(argv): def main(argv):
global CONFIG, TCP_IP, TCP_PORT, VNC_PASSWORD, threads, controlthread class vnc_config:
class CONFIG: pass
_8bitdither = False
parser = ArgumentParser() 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') 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') 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("-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() args = parser.parse_args()
if args.OUTFILE is not None: if args.outfile is not None:
fsock = open(args.OUTFILE, 'w') try:
fsock = open(args.outfile, 'w')
except Exception as ex:
print("Error:", ex, file=sys.stderr)
sys.exit(1)
sys.stdout = sys.stderr = fsock sys.stdout = sys.stderr = fsock
# Multithreaded Python server vnc_config.vnc_password = args.vnc_password
TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP vnc_config.eightbitdither = args.dither
TCP_PORT = '5901' if not hasattr(args,"TCP_PORT") else args.TCP_PORT vnc_config.auth_type = args.auth_type
VNC_PASSWORD = args.VNC_PASSWORD vnc_config.pem_file = args.pem_file
CONFIG._8bitdither = args.dither vnc_config.win_title = args.win_title
sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sockServer.bind((TCP_IP, TCP_PORT)) sockServer.bind((args.listen_addr, args.listen_port))
controlthread = ControlThread(threads)
controlthread.start()
threads.append(controlthread)
_debug("Multithreaded Python server : Waiting for connections from TCP clients...") _debug("Multithreaded Python server : Waiting for connections from TCP clients...")
_debug("Runing on:", sys.platform) _debug("Runing on:", sys.platform)
@@ -111,21 +116,16 @@ def main(argv):
while True: while True:
sockServer.listen(4) sockServer.listen(4)
(conn, (ip,port)) = sockServer.accept() (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.setDaemon(True)
newthread.start() newthread.start()
threads.append(newthread)
#print(threads)
if __name__ == "__main__": if __name__ == "__main__":
try: try:
threads = []
main(sys.argv) main(sys.argv)
except KeyboardInterrupt: except KeyboardInterrupt:
# quit # quit
_debug("Exiting on ctrl+c...") _debug("Exiting on ctrl+c...")
#for t in threads:
# _debug("Killing", t)
sys.exit() sys.exit()