add connect response reading

This commit is contained in:
speyrefitte
2013-10-25 17:36:34 +02:00
parent 1070ea8b6a
commit 963e20dc9f
8 changed files with 182 additions and 65 deletions

View File

@@ -46,3 +46,13 @@ class InvalidType(Exception):
'''
Exception.__init__(self, message)
class InvalidSize(Exception):
'''
raise when invalid size is present in packet type occured
'''
def __init__(self, message = ""):
'''
constructor with message
@param message: message show when exception is raised
'''
Exception.__init__(self, message)

View File

@@ -3,6 +3,7 @@
'''
import struct
from copy import deepcopy
from StringIO import StringIO
from error import InvalidValue, InvalidType
@@ -240,6 +241,28 @@ class CompositeType(Type):
size += sizeof(self.__dict__[name])
return size
def __eq__(self, other):
'''
compare each properties which are Type inheritance
if one is different then not equal
@param other: CompositeType
@return: True if each subtype are equals
'''
if self._typeName != other._typeName:
return False
for name in self._typeName:
if self.__dict__[name] != other.__dict__[name]:
return False
return True
def __ne__(self, other):
'''
return not equal result operator
@param other: CompositeType
@return: False if each subtype are equals
'''
return not self.__eq__(other)
class UInt8(SimpleType):
'''
unsigned byte
@@ -460,15 +483,29 @@ class Stream(StringIO):
self.writeType(element)
return
value.write(self)
def write_unistr(self, value):
for c in value:
self.write_uint8(ord(c))
self.write_uint8(0)
self.write_uint8(0)
self.write_uint8(0)
def CheckValueOnRead(cls):
'''
wrap read method of class
to check value on read
if new value is different from old value
raise InvalidValue
@param cls: class that inherit from Type
'''
oldRead = cls.read
def read(self, s):
old = deepcopy(self)
oldRead(self, s)
if self != old:
raise InvalidValue("CheckValueOnRead %s != %s"%(self, old))
cls.read = read
return cls
def hexDump(src, length=16):
'''
print hex representation of sr
@param src: string
'''
FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])
for c in xrange(0, len(src), length):
chars = src[c:c+length]

View File

@@ -3,7 +3,8 @@
'''
from rdpy.protocol.network.type import UInt8, UInt16Be, UInt32Be, String
from rdpy.utils.const import ConstAttributes
from rdpy.protocol.network.error import InvalidExpectedDataException
from rdpy.protocol.network.error import InvalidExpectedDataException,\
InvalidSize
@ConstAttributes
class BerPc(object):
@@ -228,9 +229,8 @@ def readEnumerated(s):
'''
if not readUniversalTag(s, Tag.BER_TAG_ENUMERATED, False):
raise InvalidExpectedDataException("invalid ber tag")
size = readLength(s)
if size != UInt32Be(1):
raise InvalidExpectedDataException("enumerate size is wrong")
if readLength(s) != 1:
raise InvalidSize("enumerate size is wrong")
enumer = UInt8()
s.readType(enumer)
return enumer.value

View File

@@ -2,28 +2,30 @@
@author: sylvain
'''
from rdpy.utils.const import ConstAttributes
from rdpy.utils.const import ConstAttributes, TypeAttributes
from rdpy.protocol.network.layer import LayerAutomata
from rdpy.protocol.network.type import sizeof, Stream, UInt8
from rdpy.protocol.rdp.ber import writeLength
from rdpy.protocol.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
import ber, gcc
@ConstAttributes
@TypeAttributes(UInt8)
class Message(object):
'''
message type
'''
MCS_TYPE_CONNECT_INITIAL = UInt8(0x65)
MCS_TYPE_CONNECT_RESPONSE = UInt8(0x66)
MCS_EDRQ = UInt8(1)
MCS_DPUM = UInt8(8)
MCS_AURQ = UInt8(10)
MCS_AUCF = UInt8(11)
MCS_CJRQ = UInt8(14)
MCS_CJCF = UInt8(15)
MCS_SDRQ = UInt8(25)
MCS_SDIN = UInt8(26)
MCS_TYPE_CONNECT_INITIAL = 0x65
MCS_TYPE_CONNECT_RESPONSE = 0x66
MCS_EDRQ = 1
MCS_DPUM = 8
MCS_AURQ = 10
MCS_AUCF = 11
MCS_CJRQ = 14
MCS_CJCF = 15
MCS_SDRQ = 25
MCS_SDIN = 26
class Channel:
MCS_GLOBAL_CHANNEL = 1003
@@ -66,6 +68,8 @@ class MCS(LayerAutomata):
self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff),
ber.writeOctetstring(ccReqStream.getvalue()))
self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp))
#we must receive a connect response
self.setNextState(self.recvConnectResponse)
def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize):
'''
@@ -81,5 +85,34 @@ class MCS(LayerAutomata):
ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1),
ber.writeInteger(maxPduSize), ber.writeInteger(2))
return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domainParam)), domainParam)
def readDomainParams(self, s):
'''
read domain params structure
'''
if not ber.readUniversalTag(s, ber.Tag.BER_TAG_SEQUENCE, True):
raise InvalidValue("bad BER tags")
length = ber.readLength(s)
max_channels = ber.readInteger(s)
max_users = ber.readInteger(s)
max_tokens = ber.readInteger(s)
ber.readInteger(s)
ber.readInteger(s)
ber.readInteger(s)
max_pdu_size = ber.readInteger(s)
ber.readInteger(s)
def recvConnectResponse(self, data):
ber.readApplicationTag(data, Message.MCS_TYPE_CONNECT_RESPONSE)
ber.readEnumerated(data)
ber.readInteger(data)
self.readDomainParams(data)
if not ber.readUniversalTag(data, ber.Tag.BER_TAG_OCTET_STRING, False):
raise InvalidExpectedDataException("invalid expected tag")
gccRequestLength = ber.readLength(data)
if data.dataLen() != gccRequestLength:
raise InvalidSize("gcc request have ")
from rdpy.protocol.network.type import hexDump
hexDump(data.getvalue())

View File

@@ -2,7 +2,7 @@
@author: sylvain
'''
from rdpy.protocol.network.type import UInt8, UInt16Be, UInt32Be, String, Stream
from rdpy.protocol.network.type import UInt8, UInt16Be, UInt32Be, String
from rdpy.protocol.network.error import InvalidValue, InvalidExpectedDataException
def readLength(s):

View File

@@ -4,37 +4,40 @@
from rdpy.protocol.network.layer import LayerAutomata
from rdpy.protocol.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
from rdpy.protocol.network.error import InvalidExpectedDataException, NegotiationFailure
from rdpy.utils.const import ConstAttributes
from rdpy.utils.const import ConstAttributes, TypeAttributes
@ConstAttributes
@TypeAttributes(UInt8)
class MessageType(object):
'''
message type
'''
X224_TPDU_CONNECTION_REQUEST = UInt8(0xE0)
X224_TPDU_CONNECTION_CONFIRM = UInt8(0xD0)
X224_TPDU_DISCONNECT_REQUEST = UInt8(0x80)
X224_TPDU_DATA = UInt8(0xF0)
X224_TPDU_ERROR = UInt8(0x70)
X224_TPDU_CONNECTION_REQUEST = 0xE0
X224_TPDU_CONNECTION_CONFIRM = 0xD0
X224_TPDU_DISCONNECT_REQUEST = 0x80
X224_TPDU_DATA = 0xF0
X224_TPDU_ERROR = 0x70
@ConstAttributes
@TypeAttributes(UInt8)
class NegociationType(object):
'''
negotiation header
'''
TYPE_RDP_NEG_REQ = UInt8(0x01)
TYPE_RDP_NEG_RSP = UInt8(0x02)
TYPE_RDP_NEG_FAILURE = UInt8(0x03)
TYPE_RDP_NEG_REQ = 0x01
TYPE_RDP_NEG_RSP = 0x02
TYPE_RDP_NEG_FAILURE = 0x03
@ConstAttributes
@TypeAttributes(UInt32Le)
class Protocols(object):
'''
protocols available for TPDU layer
'''
PROTOCOL_RDP = UInt32Le(0x00000000)
PROTOCOL_SSL = UInt32Le(0x00000001)
PROTOCOL_HYBRID = UInt32Le(0x00000002)
PROTOCOL_HYBRID_EX = UInt32Le(0x00000008)
PROTOCOL_RDP = 0x00000000
PROTOCOL_SSL = 0x00000001
PROTOCOL_HYBRID = 0x00000002
PROTOCOL_HYBRID_EX = 0x00000008
class TPDUConnectHeader(CompositeType):
'''
@@ -46,6 +49,15 @@ class TPDUConnectHeader(CompositeType):
self.code = code
self.padding = (UInt16Be(), UInt16Be(), UInt8())
class TPDUDataHeader(CompositeType):
'''
header send when tpdu exchange application data
'''
def __init__(self):
CompositeType.__init__(self)
self.header = UInt8(2)
self.messageType = MessageType.X224_TPDU_DATA
self.separator = UInt8(0x80)
class Negotiation(CompositeType):
'''
@@ -69,7 +81,6 @@ class TPDU(LayerAutomata):
@param presentation: MCS layer
'''
LayerAutomata.__init__(self, presentation)
#default protocol is SSl because is the only supported
#in this version of RDPY
self._protocol = Protocols.PROTOCOL_SSL
@@ -103,9 +114,19 @@ class TPDU(LayerAutomata):
LayerAutomata.connect(self)
def recvData(self, data):
print "TPDU data"
from rdpy.protocol.network.type import hexDump
hexDump(data.getvalue())
'''
read data header from packet
and pass to presentation layer
@param data: stream
'''
header = TPDUDataHeader()
data.readType(header)
if header.messageType == MessageType.X224_TPDU_DATA:
LayerAutomata.recv(self, data)
elif header.messageType == MessageType.X224_TPDU_ERROR:
raise Exception("receive error from tpdu layer")
else:
raise InvalidExpectedDataException("unknow tpdu code %s"%header.messageType)
def sendConnectionRequest(self):
'''
@@ -121,7 +142,7 @@ class TPDU(LayerAutomata):
write message packet for TPDU layer
add TPDU header
'''
self._transport.send((UInt8(2), MessageType.X224_TPDU_DATA, UInt8(0x80), message))
self._transport.send((TPDUDataHeader(), message))
def readNeg(self, data):
'''

View File

@@ -3,58 +3,63 @@
'''
from rdpy.protocol.network.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType
from rdpy.utils.const import ConstAttributes
from rdpy.utils.const import ConstAttributes, TypeAttributes
@ConstAttributes
@TypeAttributes(String)
class ProtocolVersion(object):
'''
different ptotocol version
'''
UNKNOWN = String()
RFB003003 = String("RFB 003.003\n")
RFB003007 = String("RFB 003.007\n")
RFB003008 = String("RFB 003.008\n")
UNKNOWN = ""
RFB003003 = "RFB 003.003\n"
RFB003007 = "RFB 003.007\n"
RFB003008 = "RFB 003.008\n"
@ConstAttributes
@TypeAttributes(UInt8)
class SecurityType(object):
'''
security type supported
(or will be supported)
by rdpy
'''
INVALID = UInt8(0)
NONE = UInt8(1)
VNC = UInt8(2)
INVALID = 0
NONE = 1
VNC = 2
@ConstAttributes
@TypeAttributes(UInt32Be)
class Pointer(object):
'''
mouse event code (which button)
actually in RFB specification only$
three buttons are supported
'''
BUTTON1 = UInt32Be(0x1)
BUTTON2 = UInt32Be(0x2)
BUTTON3 = UInt32Be(0x4)
BUTTON1 = 0x1
BUTTON2 = 0x2
BUTTON3 = 0x4
@ConstAttributes
@ConstAttributes
@TypeAttributes(SInt32Be)
class Encoding(object):
'''
encoding types
'''
RAW = SInt32Be(0)
RAW = 0
@ConstAttributes
@TypeAttributes(UInt8)
class ClientToServerMessages(object):
'''
messages types
'''
PIXEL_FORMAT = UInt8(0)
ENCODING = UInt8(2)
FRAME_BUFFER_UPDATE_REQUEST = UInt8(3)
KEY_EVENT = UInt8(4)
POINTER_EVENT = UInt8(5)
CUT_TEXT = UInt8(6)
PIXEL_FORMAT = 0
ENCODING = 2
FRAME_BUFFER_UPDATE_REQUEST = 3
KEY_EVENT = 4
POINTER_EVENT = 5
CUT_TEXT = 6
class PixelFormat(CompositeType):
'''

View File

@@ -33,16 +33,27 @@ class Constant(object):
delete is forbidden on constant
'''
raise Exception("can't delete constant")
def TypeAttributes(typeClass):
'''
call typeClass ctor on each attributes
to uniform atributes type on class
@param typeClass: class use to construct each class attributes
@return: class decorator
'''
def wrapper(cls):
for c_name, c_value in cls.__dict__.iteritems():
if c_name[0] != '_' and not callable(c_value):
setattr(cls, c_name, typeClass(c_value))
return cls
return wrapper
def ConstAttributes(cls):
'''
copy on read attributes
transform all attributes of class
in constant attribute
only attributes which are not begining with '_' char
and are not callable
'''
for c_name, c_value in cls.__dict__.iteritems():
if c_name[0] != '_' and not callable(c_value):
setattr(cls, c_name, Constant(c_value))
return cls
return TypeAttributes(Constant)(cls)