Add license header + SSL server config
This commit is contained in:
@@ -10,4 +10,10 @@ Remote Desktop Protocol in Twisted Python
|
|||||||
* python-qt4
|
* python-qt4
|
||||||
* python-qt4reactor
|
* python-qt4reactor
|
||||||
|
|
||||||
|
##Must be implemented before first release
|
||||||
|
* CreedSSP
|
||||||
|
* Packet redirection
|
||||||
|
* License
|
||||||
|
* Most common orders
|
||||||
|
|
||||||
this project is still in progress.
|
this project is still in progress.
|
||||||
|
|||||||
@@ -7,9 +7,18 @@ import sys, os
|
|||||||
sys.path.insert(1, os.path.join(sys.path[0], '../..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '../..'))
|
||||||
|
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.protocol.rdp import rdp
|
||||||
from rdpy.network.layer import LayerMode
|
|
||||||
|
class TestServerFactory(rdp.ServerFactory):
|
||||||
|
def startedConnecting(self, connector):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def clientConnectionLost(self, connector, reason):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def clientConnectionFailed(self, connector, reason):
|
||||||
|
pass
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
reactor.listenTCP(33389, rdp.Factory(LayerMode.SERVER))
|
reactor.listenTCP(33389, TestServerFactory())
|
||||||
reactor.run()
|
reactor.run()
|
||||||
@@ -47,7 +47,7 @@ class ClientFactory(protocol.Factory):
|
|||||||
'''
|
'''
|
||||||
pduLayer = pdu.PDU(LayerMode.CLIENT)
|
pduLayer = pdu.PDU(LayerMode.CLIENT)
|
||||||
pduLayer.getController().addObserver(self.buildObserver())
|
pduLayer.getController().addObserver(self.buildObserver())
|
||||||
return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pduLayer)));
|
return tpkt.TPKT(tpdu.createClient(mcs.MCS(pduLayer)));
|
||||||
|
|
||||||
def buildObserver(self):
|
def buildObserver(self):
|
||||||
'''
|
'''
|
||||||
@@ -55,6 +55,33 @@ class ClientFactory(protocol.Factory):
|
|||||||
'''
|
'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ServerFactory(protocol.Factory):
|
||||||
|
'''
|
||||||
|
Factory of Serrve RDP protocol
|
||||||
|
'''
|
||||||
|
def __init__(self, privateKeyFileName, certificateFileName):
|
||||||
|
'''
|
||||||
|
ctor
|
||||||
|
@param privateKeyFileName: file contain server private key
|
||||||
|
@param certficiateFileName: file that contain publi key
|
||||||
|
'''
|
||||||
|
self._privateKeyFileName = privateKeyFileName
|
||||||
|
self._certificateFileName = certificateFileName
|
||||||
|
|
||||||
|
def buildProtocol(self, addr):
|
||||||
|
'''
|
||||||
|
Function call from twisted and build rdp protocol stack
|
||||||
|
@param addr: destination address
|
||||||
|
'''
|
||||||
|
pduLayer = pdu.PDU(LayerMode.SERVER)
|
||||||
|
#pduLayer.getController().addObserver(self.buildObserver())
|
||||||
|
return tpkt.TPKT(tpdu.createServer(mcs.MCS(pduLayer), self._privateKeyFileName, self._certificateFileName));
|
||||||
|
|
||||||
|
def buildObserver(self):
|
||||||
|
'''
|
||||||
|
build observer use for connection
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
class RDPClientObserver(object):
|
class RDPClientObserver(object):
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -1,6 +1,29 @@
|
|||||||
'''
|
#
|
||||||
@author: sylvain
|
# Copyright (c) 2014 Sylvain Peyrefitte
|
||||||
'''
|
#
|
||||||
|
# This file is part of rdpy.
|
||||||
|
#
|
||||||
|
# rdpy is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Implement transport pdu layer
|
||||||
|
|
||||||
|
This layer have main goal to negociate ssl transport
|
||||||
|
RDP basic security is not supported by RDPY (because is not a true security layer...)
|
||||||
|
"""
|
||||||
|
|
||||||
from rdpy.network.layer import LayerAutomata, LayerMode
|
from rdpy.network.layer import LayerAutomata, LayerMode
|
||||||
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
|
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
|
||||||
from rdpy.network.error import InvalidExpectedDataException
|
from rdpy.network.error import InvalidExpectedDataException
|
||||||
@@ -9,9 +32,9 @@ from rdpy.network.const import ConstAttributes, TypeAttributes
|
|||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt8)
|
@TypeAttributes(UInt8)
|
||||||
class MessageType(object):
|
class MessageType(object):
|
||||||
'''
|
"""
|
||||||
message type
|
message type
|
||||||
'''
|
"""
|
||||||
X224_TPDU_CONNECTION_REQUEST = 0xE0
|
X224_TPDU_CONNECTION_REQUEST = 0xE0
|
||||||
X224_TPDU_CONNECTION_CONFIRM = 0xD0
|
X224_TPDU_CONNECTION_CONFIRM = 0xD0
|
||||||
X224_TPDU_DISCONNECT_REQUEST = 0x80
|
X224_TPDU_DISCONNECT_REQUEST = 0x80
|
||||||
@@ -21,9 +44,9 @@ class MessageType(object):
|
|||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt8)
|
@TypeAttributes(UInt8)
|
||||||
class NegociationType(object):
|
class NegociationType(object):
|
||||||
'''
|
"""
|
||||||
negotiation header
|
negotiation header
|
||||||
'''
|
"""
|
||||||
TYPE_RDP_NEG_REQ = 0x01
|
TYPE_RDP_NEG_REQ = 0x01
|
||||||
TYPE_RDP_NEG_RSP = 0x02
|
TYPE_RDP_NEG_RSP = 0x02
|
||||||
TYPE_RDP_NEG_FAILURE = 0x03
|
TYPE_RDP_NEG_FAILURE = 0x03
|
||||||
@@ -31,9 +54,9 @@ class NegociationType(object):
|
|||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt32Le)
|
@TypeAttributes(UInt32Le)
|
||||||
class Protocols(object):
|
class Protocols(object):
|
||||||
'''
|
"""
|
||||||
protocols available for TPDU layer
|
protocols available for TPDU layer
|
||||||
'''
|
"""
|
||||||
PROTOCOL_RDP = 0x00000000
|
PROTOCOL_RDP = 0x00000000
|
||||||
PROTOCOL_SSL = 0x00000001
|
PROTOCOL_SSL = 0x00000001
|
||||||
PROTOCOL_HYBRID = 0x00000002
|
PROTOCOL_HYBRID = 0x00000002
|
||||||
@@ -42,9 +65,9 @@ class Protocols(object):
|
|||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt32Le)
|
@TypeAttributes(UInt32Le)
|
||||||
class NegotiationFailureCode(object):
|
class NegotiationFailureCode(object):
|
||||||
'''
|
"""
|
||||||
protocol negotiation failure code
|
protocol negotiation failure code
|
||||||
'''
|
"""
|
||||||
SSL_REQUIRED_BY_SERVER = 0x00000001
|
SSL_REQUIRED_BY_SERVER = 0x00000001
|
||||||
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002
|
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002
|
||||||
SSL_CERT_NOT_ON_SERVER = 0x00000003
|
SSL_CERT_NOT_ON_SERVER = 0x00000003
|
||||||
@@ -53,10 +76,13 @@ class NegotiationFailureCode(object):
|
|||||||
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
|
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
|
||||||
|
|
||||||
class TPDUConnectMessage(CompositeType):
|
class TPDUConnectMessage(CompositeType):
|
||||||
'''
|
"""
|
||||||
header of TPDU connection messages
|
header of TPDU connection messages
|
||||||
'''
|
"""
|
||||||
def __init__(self, code):
|
def __init__(self, code):
|
||||||
|
"""
|
||||||
|
@param code: MessageType
|
||||||
|
"""
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
self.len = UInt8(lambda:sizeof(self) - 1)
|
self.len = UInt8(lambda:sizeof(self) - 1)
|
||||||
self.code = UInt8(code.value, constant = True)
|
self.code = UInt8(code.value, constant = True)
|
||||||
@@ -65,9 +91,9 @@ class TPDUConnectMessage(CompositeType):
|
|||||||
self.protocolNeg = Negotiation(optional = True)
|
self.protocolNeg = Negotiation(optional = True)
|
||||||
|
|
||||||
class TPDUDataHeader(CompositeType):
|
class TPDUDataHeader(CompositeType):
|
||||||
'''
|
"""
|
||||||
header send when tpdu exchange application data
|
header send when tpdu exchange application data
|
||||||
'''
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
self.header = UInt8(2, constant = True)
|
self.header = UInt8(2, constant = True)
|
||||||
@@ -75,12 +101,12 @@ class TPDUDataHeader(CompositeType):
|
|||||||
self.separator = UInt8(0x80, constant = True)
|
self.separator = UInt8(0x80, constant = True)
|
||||||
|
|
||||||
class Negotiation(CompositeType):
|
class Negotiation(CompositeType):
|
||||||
'''
|
"""
|
||||||
negociation request message
|
negociate request message
|
||||||
@see: request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
@see: request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
||||||
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
||||||
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
||||||
'''
|
"""
|
||||||
def __init__(self, optional = False):
|
def __init__(self, optional = False):
|
||||||
CompositeType.__init__(self, optional = optional)
|
CompositeType.__init__(self, optional = optional)
|
||||||
self.code = UInt8()
|
self.code = UInt8()
|
||||||
@@ -91,16 +117,16 @@ class Negotiation(CompositeType):
|
|||||||
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
|
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
|
||||||
|
|
||||||
class TPDU(LayerAutomata):
|
class TPDU(LayerAutomata):
|
||||||
'''
|
"""
|
||||||
TPDU layer management
|
TPDU layer management
|
||||||
there is an connection automata
|
there is an connection automata
|
||||||
'''
|
"""
|
||||||
def __init__(self, presentation):
|
def __init__(self, mode, presentation):
|
||||||
'''
|
"""
|
||||||
Constructor
|
@param mode: automata mode (client or server)
|
||||||
@param presentation: MCS layer
|
@param presentation: upper layer, MCS layer in RDP case
|
||||||
'''
|
"""
|
||||||
LayerAutomata.__init__(self, presentation._mode, presentation)
|
LayerAutomata.__init__(self, mode, presentation)
|
||||||
#default selectedProtocol is SSl because is the only supported
|
#default selectedProtocol is SSl because is the only supported
|
||||||
#in this version of RDPY
|
#in this version of RDPY
|
||||||
#client requested selectedProtocol
|
#client requested selectedProtocol
|
||||||
@@ -108,25 +134,38 @@ class TPDU(LayerAutomata):
|
|||||||
#server selected selectedProtocol
|
#server selected selectedProtocol
|
||||||
self._selectedProtocol = Protocols.PROTOCOL_SSL
|
self._selectedProtocol = Protocols.PROTOCOL_SSL
|
||||||
|
|
||||||
|
#Server mode informations for tls connexion
|
||||||
|
self._serverPrivateKeyFileName = None
|
||||||
|
self._serverCertificateFileName = None
|
||||||
|
|
||||||
|
def initTLSServerInfos(self, privateKeyFileName, certificateFileName):
|
||||||
|
"""
|
||||||
|
Init informations for ssl server connexion
|
||||||
|
@param privateKeyFileName: file contain server private key
|
||||||
|
@param certficiateFileName: file that contain publi key
|
||||||
|
"""
|
||||||
|
self._serverPrivateKeyFileName = privateKeyFileName
|
||||||
|
self._serverCertificateFileName = certificateFileName
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
"""
|
||||||
connection request
|
connection request
|
||||||
for client send a connection request packet
|
for client send a connection request packet
|
||||||
'''
|
"""
|
||||||
if self._mode == LayerMode.CLIENT:
|
if self._mode == LayerMode.CLIENT:
|
||||||
self.sendConnectionRequest()
|
self.sendConnectionRequest()
|
||||||
else:
|
else:
|
||||||
self.setNextState(self.recvConnectionRequest)
|
self.setNextState(self.recvConnectionRequest)
|
||||||
|
|
||||||
def recvConnectionConfirm(self, data):
|
def recvConnectionConfirm(self, data):
|
||||||
'''
|
"""
|
||||||
recv connection confirm message
|
receive connection confirm message
|
||||||
next state is recvData
|
next state is recvData
|
||||||
call connect on presentation layer if all is good
|
call connect on presentation layer if all is good
|
||||||
@param data: Stream that contain connection confirm
|
@param data: Stream that contain connection confirm
|
||||||
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
||||||
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
||||||
'''
|
"""
|
||||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
|
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
|
||||||
data.readType(message)
|
data.readType(message)
|
||||||
|
|
||||||
@@ -150,12 +189,12 @@ class TPDU(LayerAutomata):
|
|||||||
LayerAutomata.connect(self)
|
LayerAutomata.connect(self)
|
||||||
|
|
||||||
def recvConnectionRequest(self, data):
|
def recvConnectionRequest(self, data):
|
||||||
'''
|
"""
|
||||||
read connection confirm packet
|
read connection confirm packet
|
||||||
next state is send connection confirm
|
next state is send connection confirm
|
||||||
@param data: stream
|
@param data: Stream
|
||||||
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
|
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
|
||||||
'''
|
"""
|
||||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
|
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
|
||||||
data.readType(message)
|
data.readType(message)
|
||||||
|
|
||||||
@@ -177,21 +216,21 @@ class TPDU(LayerAutomata):
|
|||||||
self.sendConnectionConfirm()
|
self.sendConnectionConfirm()
|
||||||
|
|
||||||
def recvData(self, data):
|
def recvData(self, data):
|
||||||
'''
|
"""
|
||||||
read data header from packet
|
read data header from packet
|
||||||
and pass to presentation layer
|
and pass to presentation layer
|
||||||
@param data: stream
|
@param data: Stream
|
||||||
'''
|
"""
|
||||||
header = TPDUDataHeader()
|
header = TPDUDataHeader()
|
||||||
data.readType(header)
|
data.readType(header)
|
||||||
LayerAutomata.recv(self, data)
|
LayerAutomata.recv(self, data)
|
||||||
|
|
||||||
def sendConnectionRequest(self):
|
def sendConnectionRequest(self):
|
||||||
'''
|
"""
|
||||||
write connection request message
|
write connection request message
|
||||||
next state is recvConnectionConfirm
|
next state is recvConnectionConfirm
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
||||||
'''
|
"""
|
||||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
|
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
|
||||||
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
|
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
|
||||||
message.protocolNeg.selectedProtocol = self._requestedProtocol
|
message.protocolNeg.selectedProtocol = self._requestedProtocol
|
||||||
@@ -199,36 +238,53 @@ class TPDU(LayerAutomata):
|
|||||||
self.setNextState(self.recvConnectionConfirm)
|
self.setNextState(self.recvConnectionConfirm)
|
||||||
|
|
||||||
def sendConnectionConfirm(self):
|
def sendConnectionConfirm(self):
|
||||||
'''
|
"""
|
||||||
write connection confirm message
|
write connection confirm message
|
||||||
next state is recvData
|
next state is recvData
|
||||||
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
|
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
|
||||||
'''
|
"""
|
||||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
|
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
|
||||||
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
|
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
|
||||||
message.protocolNeg.selectedProtocol = self._selectedProtocol
|
message.protocolNeg.selectedProtocol = self._selectedProtocol
|
||||||
self._transport.send(message)
|
self._transport.send(message)
|
||||||
#_transport is TPKT and transport is TCP layer of twisted
|
#_transport is TPKT and transport is TCP layer of twisted
|
||||||
self._transport.transport.startTLS(ServerTLSContext())
|
self._transport.transport.startTLS(ServerTLSContext(self._serverPrivateKeyFileName, self._serverCertificateFileName))
|
||||||
#connection is done send to presentation
|
#connection is done send to presentation
|
||||||
LayerAutomata.connect(self)
|
LayerAutomata.connect(self)
|
||||||
|
|
||||||
def send(self, message):
|
def send(self, message):
|
||||||
'''
|
"""
|
||||||
write message packet for TPDU layer
|
write message packet for TPDU layer
|
||||||
add TPDU header
|
add TPDU header
|
||||||
'''
|
@param message: network.Type message
|
||||||
|
"""
|
||||||
self._transport.send((TPDUDataHeader(), message))
|
self._transport.send((TPDUDataHeader(), message))
|
||||||
|
|
||||||
|
def createClient(presentation):
|
||||||
|
"""
|
||||||
|
Factory of TPDU layer in Client mode
|
||||||
|
@param presentation: presentation layer, in RDP mode is MCS layer
|
||||||
|
"""
|
||||||
|
return TPDU(LayerMode.CLIENT, presentation)
|
||||||
|
|
||||||
|
def createServer(presentation, privateKeyFileName, certificateFileName):
|
||||||
|
"""
|
||||||
|
Factory of TPDU layer in Server mode
|
||||||
|
@param privateKeyFileName: file contain server private key
|
||||||
|
@param certficiateFileName: file that contain publi key
|
||||||
|
"""
|
||||||
|
tpdu = TPDU(LayerMode.SERVER, presentation)
|
||||||
|
tpdu.initTLSServerInfos(privateKeyFileName, certificateFileName)
|
||||||
|
return tpdu
|
||||||
|
|
||||||
#open ssl needed
|
#open ssl needed
|
||||||
from twisted.internet import ssl
|
from twisted.internet import ssl
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
|
|
||||||
class ClientTLSContext(ssl.ClientContextFactory):
|
class ClientTLSContext(ssl.ClientContextFactory):
|
||||||
'''
|
"""
|
||||||
client context factory for open ssl
|
client context factory for open ssl
|
||||||
'''
|
"""
|
||||||
def getContext(self):
|
def getContext(self):
|
||||||
context = SSL.Context(SSL.TLSv1_METHOD)
|
context = SSL.Context(SSL.TLSv1_METHOD)
|
||||||
context.set_options(0x00020000)#SSL_OP_NO_COMPRESSION
|
context.set_options(0x00020000)#SSL_OP_NO_COMPRESSION
|
||||||
@@ -237,9 +293,10 @@ class ClientTLSContext(ssl.ClientContextFactory):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
|
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
|
||||||
'''
|
"""
|
||||||
server context factory for open ssl
|
server context factory for open ssl
|
||||||
'''
|
@param privateKeyFileName: Name of a file containing a private key
|
||||||
def __init__(self, *args, **kw):
|
@param certificateFileName: Name of a file containing a certificate
|
||||||
kw['sslmethod'] = SSL.TLSv1_METHOD
|
"""
|
||||||
ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kw)
|
def __init__(self, privateKeyFileName, certificateFileName):
|
||||||
|
ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, SSL.TLSv1_METHOD)
|
||||||
@@ -1,22 +1,44 @@
|
|||||||
'''
|
#
|
||||||
@author: sylvain
|
# Copyright (c) 2014 Sylvain Peyrefitte
|
||||||
'''
|
#
|
||||||
|
# This file is part of rdpy.
|
||||||
|
#
|
||||||
|
# rdpy is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Transport packet layer implementation
|
||||||
|
|
||||||
|
Use to build correct size packet and handle slow path and fast path mode
|
||||||
|
"""
|
||||||
from rdpy.network.layer import RawLayer, LayerMode
|
from rdpy.network.layer import RawLayer, LayerMode
|
||||||
from rdpy.network.type import UInt8, UInt16Be, sizeof
|
from rdpy.network.type import UInt8, UInt16Be, sizeof
|
||||||
|
|
||||||
class TPKT(RawLayer):
|
class TPKT(RawLayer):
|
||||||
'''
|
"""
|
||||||
TPKT layer in RDP protocol stack
|
TPKT layer in RDP protocol stack
|
||||||
this layer only handle size of packet
|
this layer only handle size of packet
|
||||||
and determine if is a fast path packet
|
and determine if is a fast path packet
|
||||||
'''
|
"""
|
||||||
#first byte of classic tpkt header
|
#first byte of classic tpkt header
|
||||||
TPKT_PACKET = UInt8(3)
|
TPKT_PACKET = UInt8(3)
|
||||||
|
|
||||||
def __init__(self, presentation):
|
def __init__(self, presentation):
|
||||||
'''
|
"""
|
||||||
Constructor
|
Constructor
|
||||||
'''
|
@param presentation: presentation layer, in RDP case is TPDU layer
|
||||||
|
"""
|
||||||
RawLayer.__init__(self, LayerMode.NONE, presentation)
|
RawLayer.__init__(self, LayerMode.NONE, presentation)
|
||||||
#last packet version read from header
|
#last packet version read from header
|
||||||
self._lastPacketVersion = UInt8()
|
self._lastPacketVersion = UInt8()
|
||||||
@@ -24,10 +46,10 @@ class TPKT(RawLayer):
|
|||||||
self._lastShortLength = UInt8()
|
self._lastShortLength = UInt8()
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
"""
|
||||||
call when transport layer connection
|
call when transport layer connection
|
||||||
is made (inherit from RawLayer)
|
is made (inherit from RawLayer)
|
||||||
'''
|
"""
|
||||||
#header is on two bytes
|
#header is on two bytes
|
||||||
self.expect(2, self.readHeader)
|
self.expect(2, self.readHeader)
|
||||||
#no connection automata on this layer
|
#no connection automata on this layer
|
||||||
@@ -35,9 +57,10 @@ class TPKT(RawLayer):
|
|||||||
self._presentation.connect()
|
self._presentation.connect()
|
||||||
|
|
||||||
def readHeader(self, data):
|
def readHeader(self, data):
|
||||||
'''
|
"""
|
||||||
read header of TPKT packet
|
read header of TPKT packet
|
||||||
'''
|
@param data: Stream received from twisted layer
|
||||||
|
"""
|
||||||
#first read packet version
|
#first read packet version
|
||||||
data.readType(self._lastPacketVersion)
|
data.readType(self._lastPacketVersion)
|
||||||
#classic packet
|
#classic packet
|
||||||
@@ -57,18 +80,20 @@ class TPKT(RawLayer):
|
|||||||
|
|
||||||
|
|
||||||
def readExtendedHeader(self, data):
|
def readExtendedHeader(self, data):
|
||||||
'''
|
"""
|
||||||
header may be on 4 bytes
|
header may be on 4 bytes
|
||||||
'''
|
@param data: Stream from twisted layer
|
||||||
|
"""
|
||||||
#next state is read data
|
#next state is read data
|
||||||
size = UInt16Be()
|
size = UInt16Be()
|
||||||
data.readType(size)
|
data.readType(size)
|
||||||
self.expect(size.value - 4, self.readData)
|
self.expect(size.value - 4, self.readData)
|
||||||
|
|
||||||
def readExtendedFastPathHeader(self, data):
|
def readExtendedFastPathHeader(self, data):
|
||||||
'''
|
"""
|
||||||
fast ath header may be on 1 byte more
|
fast path header may be on 1 byte more
|
||||||
'''
|
@param data: Stream from twisted layer
|
||||||
|
"""
|
||||||
leftPart = UInt8()
|
leftPart = UInt8()
|
||||||
data.readType(leftPart)
|
data.readType(leftPart)
|
||||||
self._lastShortLength.value &= ~0x80
|
self._lastShortLength.value &= ~0x80
|
||||||
@@ -77,21 +102,24 @@ class TPKT(RawLayer):
|
|||||||
self.expect(self._lastShortLength.value - 3, self.readFastPath)
|
self.expect(self._lastShortLength.value - 3, self.readFastPath)
|
||||||
|
|
||||||
def readFastPath(self, data):
|
def readFastPath(self, data):
|
||||||
'''
|
"""
|
||||||
fast path data
|
fast path data
|
||||||
'''
|
@param data: Stream from twisted layer
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def readData(self, data):
|
def readData(self, data):
|
||||||
'''
|
"""
|
||||||
read classic TPKT packet
|
read classic TPKT packet, last state in tpkt automata
|
||||||
'''
|
@param data: Stream with correct size
|
||||||
|
"""
|
||||||
#next state is pass to
|
#next state is pass to
|
||||||
self._presentation.recv(data)
|
self._presentation.recv(data)
|
||||||
self.expect(2, self.readHeader)
|
self.expect(2, self.readHeader)
|
||||||
|
|
||||||
def send(self, message):
|
def send(self, message):
|
||||||
'''
|
"""
|
||||||
send encapsuled data
|
send encompassed data
|
||||||
'''
|
@param message: network.Type message to send
|
||||||
|
"""
|
||||||
RawLayer.send(self, (TPKT.TPKT_PACKET, UInt8(0), UInt16Be(sizeof(message) + 4), message))
|
RawLayer.send(self, (TPKT.TPKT_PACKET, UInt8(0), UInt16Be(sizeof(message) + 4), message))
|
||||||
Reference in New Issue
Block a user