<s> import os <EOL> import struct <EOL> import logging <EOL> from twisted . internet . protocol import Factory , Protocol <EOL> from twisted . internet import reactor <EOL> from constants import * <EOL> from packets import SSTPDataPacket , SSTPControlPacket <EOL> from utils import hexdump <EOL> from ppp import PPPDProtocol <EOL> def parseLength ( s ) : <EOL> s = chr ( ord ( s [ <NUM_LIT:0> ] ) & <NUM_LIT> ) + s [ <NUM_LIT:1> ] <EOL> return struct . unpack ( '<STR_LIT>' , s ) [ <NUM_LIT:0> ] <EOL> class SSTPProtocol ( Protocol ) : <EOL> state = SERVER_CALL_DISCONNECTED <EOL> sstpPacketLength = <NUM_LIT:0> <EOL> receiveBuffer = '<STR_LIT>' <EOL> nonce = None <EOL> pppd = None <EOL> retryCounter = <NUM_LIT:0> <EOL> def __init__ ( self ) : <EOL> self . helloTimer = reactor . callLater ( <NUM_LIT> , self . helloTimerExpired ) <EOL> def dataReceived ( self , data ) : <EOL> if self . state == SERVER_CALL_DISCONNECTED : <EOL> self . httpDataReceived ( data ) <EOL> else : <EOL> self . sstpDataReceived ( data ) <EOL> def connectionLost ( self , reason ) : <EOL> logging . debug ( '<STR_LIT>' ) <EOL> if self . pppd is not None and self . pppd . transport is not None : <EOL> self . pppd . transport . loseConnection ( ) <EOL> if self . factory . remotePool is not None : <EOL> self . factory . remotePool . unregister ( self . pppd . remote ) <EOL> if self . helloTimer . active ( ) : <EOL> self . helloTimer . cancel ( ) <EOL> def httpDataReceived ( self , data ) : <EOL> self . receiveBuffer += data <EOL> if "<STR_LIT>" not in self . receiveBuffer : <EOL> return <EOL> requestLine = self . receiveBuffer . split ( '<STR_LIT:\r\n>' ) [ <NUM_LIT:0> ] <EOL> self . receiveBuffer = '<STR_LIT>' <EOL> method , uri , version = requestLine . split ( ) <EOL> if method != "<STR_LIT>" and version != "<STR_LIT>" : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> self . transport . loseConnection ( ) <EOL> return <EOL> self . transport . write ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> self . state = SERVER_CONNECT_REQUEST_PENDING <EOL> def sstpDataReceived ( self , data ) : <EOL> self . receiveBuffer += data <EOL> while len ( self . receiveBuffer ) >= <NUM_LIT:4> : <EOL> if self . receiveBuffer [ <NUM_LIT:0> ] != '<STR_LIT>' : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> self . transport . loseConnection ( ) <EOL> return <EOL> if not self . sstpPacketLength : <EOL> self . sstpPacketLength = parseLength ( self . receiveBuffer [ <NUM_LIT:2> : <NUM_LIT:4> ] ) <EOL> if len ( self . receiveBuffer ) < self . sstpPacketLength : <EOL> return <EOL> packet = self . receiveBuffer [ : self . sstpPacketLength ] <EOL> self . receiveBuffer = self . receiveBuffer [ self . sstpPacketLength : ] <EOL> self . sstpPacketLength = <NUM_LIT:0> <EOL> self . sstpPacketReceived ( packet ) <EOL> def sstpPacketReceived ( self , packet ) : <EOL> self . helloTimer . reset ( <NUM_LIT> ) <EOL> c = ord ( packet [ <NUM_LIT:1> ] ) & <NUM_LIT> <EOL> if c == <NUM_LIT:0> : <EOL> self . sstpDataPacketReceived ( packet [ <NUM_LIT:4> : ] ) <EOL> else : <EOL> messageType = packet [ <NUM_LIT:4> : <NUM_LIT:6> ] <EOL> numAttributes = struct . unpack ( '<STR_LIT>' , packet [ <NUM_LIT:6> : <NUM_LIT:8> ] ) [ <NUM_LIT:0> ] <EOL> attributes = [ ] <EOL> attrs = packet [ <NUM_LIT:8> : ] <EOL> while len ( attributes ) < numAttributes : <EOL> id = attrs [ <NUM_LIT:1> ] <EOL> length = parseLength ( attrs [ <NUM_LIT:2> : <NUM_LIT:4> ] ) <EOL> value = attrs [ <NUM_LIT:4> : length ] <EOL> attrs = attrs [ length : ] <EOL> attributes . append ( ( id , value ) ) <EOL> self . sstpControlPacketReceived ( messageType , attributes ) <EOL> def sstpDataPacketReceived ( self , data ) : <EOL> if __debug__ : <EOL> logging . debug ( '<STR_LIT>' % len ( data ) ) <EOL> logging . log ( VERBOSE , hexdump ( data ) ) <EOL> if self . pppd is None : <EOL> print ( '<STR_LIT>' ) <EOL> return <EOL> self . pppd . writeFrame ( data ) <EOL> def sstpControlPacketReceived ( self , messageType , attributes ) : <EOL> logging . info ( '<STR_LIT>' % ord ( messageType [ <NUM_LIT:1> ] ) ) <EOL> if messageType == SSTP_MSG_CALL_CONNECT_REQUEST : <EOL> protocolId = attributes [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] <EOL> self . sstpMsgCallConnectRequestReceived ( protocolId ) <EOL> elif messageType == SSTP_MSG_CALL_CONNECTED : <EOL> attr = attributes [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] <EOL> hashType = attr [ <NUM_LIT:3> : <NUM_LIT:4> ] <EOL> nonce = attr [ <NUM_LIT:4> : <NUM_LIT> ] <EOL> certHash = attr [ <NUM_LIT> : <NUM_LIT> ] <EOL> macHash = attr [ <NUM_LIT> : <NUM_LIT> ] <EOL> self . sstpMsgCallConnectedReceived ( hashType , nonce , certHash , macHash ) <EOL> elif messageType == SSTP_MSG_CALL_ABORT : <EOL> if attributes : <EOL> self . sstpMsgCallAbort ( attributes [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] ) <EOL> else : <EOL> self . sstpMsgCallAbort ( ) <EOL> elif messageType == SSTP_MSG_CALL_DISCONNECT : <EOL> if attributes : <EOL> self . sstpMsgCallDisconnect ( attributes [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] ) <EOL> else : <EOL> self . sstpMsgCallDisconnect ( ) <EOL> elif messageType == SSTP_MSG_CALL_DISCONNECT_ACK : <EOL> self . sstpMsgCallDisconnectAck ( ) <EOL> elif messageType == SSTP_MSG_ECHO_REQUEST : <EOL> self . sstpMsgEchoRequest ( ) <EOL> elif messageType == SSTP_MSG_ECHO_RESPONSE : <EOL> self . sstpMsgEchoResponse ( ) <EOL> else : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> self . abort ( ATTRIB_STATUS_INVALID_FRAME_RECEIVED ) <EOL> def sstpMsgCallConnectRequestReceived ( self , protocolId ) : <EOL> if self . state in ( CALL_ABORT_TIMEOUT_PENDING , CALL_ABORT_PENDING , <EOL> CALL_DISCONNECT_ACK_PENDING , CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> if self . state != SERVER_CONNECT_REQUEST_PENDING : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> self . transport . loseConnection ( ) <EOL> return <EOL> if protocolId != SSTP_ENCAPSULATED_PROTOCOL_PPP : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> nak = SSTPControlPacket ( SSTP_MSG_CALL_CONNECT_NAK ) <EOL> nak . attributes = [ ( SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID , <EOL> ATTRIB_STATUS_VALUE_NOT_SUPPORTED ) ] <EOL> self . addRetryCounterOrAbrot ( ) <EOL> return <EOL> self . nonce = os . urandom ( <NUM_LIT:32> ) <EOL> ack = SSTPControlPacket ( SSTP_MSG_CALL_CONNECT_ACK ) <EOL> ack . attributes = [ ( SSTP_ATTRIB_CRYPTO_BINDING_REQ , <EOL> '<STR_LIT>' + '<STR_LIT>' + self . nonce ) ] <EOL> ack . writeTo ( self . transport . write ) <EOL> self . pppd = PPPDProtocol ( ) <EOL> self . pppd . sstp = self <EOL> if self . factory . remotePool : <EOL> self . pppd . remote = self . factory . remotePool . apply ( ) <EOL> if self . pppd . remote is None : <EOL> logging . warn ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> self . abort ( ) <EOL> else : <EOL> self . pppd . remote = '<STR_LIT>' <EOL> addressArgument = '<STR_LIT>' % ( self . factory . local , self . pppd . remote ) <EOL> reactor . spawnProcess ( self . pppd , self . factory . pppd , <EOL> args = [ '<STR_LIT>' , '<STR_LIT:file>' , self . factory . pppdConfigFile , <EOL> '<STR_LIT>' , addressArgument , <EOL> '<STR_LIT>' , str ( self . transport . getPeer ( ) . host ) ] , usePTY = True ) <EOL> self . transport . registerProducer ( self . pppd , True ) <EOL> self . pppd . resumeProducing ( ) <EOL> self . state = SERVER_CALL_CONNECTED_PENDING <EOL> def sstpMsgCallConnectedReceived ( self , hashType , nonce , certHash , macHash ) : <EOL> if self . state in ( CALL_ABORT_TIMEOUT_PENDING , CALL_ABORT_PENDING , <EOL> CALL_DISCONNECT_ACK_PENDING , CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> if self . state != SERVER_CALL_CONNECTED_PENDING : <EOL> self . abort ( ATTRIB_STATUS_UNACCEPTED_FRAME_RECEIVED ) <EOL> logging . debug ( "<STR_LIT>" , certHash . encode ( '<STR_LIT>' ) ) <EOL> logging . debug ( "<STR_LIT>" , macHash . encode ( '<STR_LIT>' ) ) <EOL> logging . debug ( "<STR_LIT>" , hex ( ord ( hashType ) ) ) <EOL> if nonce != self . nonce : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> self . abort ( ATTRIB_STATUS_INVALID_FRAME_RECEIVED ) <EOL> return <EOL> self . nonce = None <EOL> if certHash is not None and certHash not in self . factory . certHash : <EOL> logging . warning ( "<STR_LIT>" <EOL> "<STR_LIT>" ) <EOL> self . abort ( ATTRIB_STATUS_INVALID_FRAME_RECEIVED ) <EOL> return <EOL> self . state = SERVER_CALL_CONNECTED <EOL> logging . info ( '<STR_LIT>' ) <EOL> def sstpMsgCallAbort ( self , status = None ) : <EOL> if self . state in ( CALL_ABORT_TIMEOUT_PENDING , <EOL> CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> logging . warn ( "<STR_LIT>" ) <EOL> if self . state == CALL_ABORT_PENDING : <EOL> reactor . callLater ( <NUM_LIT:1> , self . transport . loseConnection ) <EOL> return <EOL> self . state = CALL_ABORT_IN_PROGRESS_2 <EOL> msg = SSTPControlPacket ( SSTP_MSG_CALL_ABORT ) <EOL> msg . writeTo ( self . transport . write ) <EOL> self . state = CALL_ABORT_PENDING <EOL> reactor . callLater ( <NUM_LIT:1> , self . transport . loseConnection ) <EOL> def sstpMsgCallDisconnect ( self , status = None ) : <EOL> if self . state in ( CALL_ABORT_TIMEOUT_PENDING , CALL_ABORT_PENDING , <EOL> CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> logging . info ( '<STR_LIT>' ) <EOL> self . state = CALL_DISCONNECT_IN_PROGRESS_2 <EOL> ack = SSTPControlPacket ( SSTP_MSG_CALL_DISCONNECT_ACK ) <EOL> ack . writeTo ( self . transport . write ) <EOL> self . state = CALL_DISCONNECT_TIMEOUT_PENDING <EOL> reactor . callLater ( <NUM_LIT:1> , self . transport . loseConnection ) <EOL> def sstpMsgCallDisconnectAck ( self ) : <EOL> if self . state == CALL_DISCONNECT_ACK_PENDING : <EOL> self . transport . loseConnection ( ) <EOL> elif self . state in ( CALL_ABORT_PENDING , CALL_ABORT_TIMEOUT_PENDING , <EOL> CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> self . abort ( ATTRIB_STATUS_UNACCEPTED_FRAME_RECEIVED ) <EOL> def sstpMsgEchoRequest ( self ) : <EOL> if self . state == SERVER_CALL_CONNECTED : <EOL> response = SSTPControlPacket ( SSTP_MSG_ECHO_RESPONSE ) <EOL> response . writeTo ( self . transport . write ) <EOL> elif self . state in ( CALL_ABORT_TIMEOUT_PENDING , CALL_ABORT_PENDING , <EOL> CALL_DISCONNECT_ACK_PENDING , CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> self . abort ( ATTRIB_STATUS_UNACCEPTED_FRAME_RECEIVED ) <EOL> def sstpMsgEchoResponse ( self ) : <EOL> if self . state == SERVER_CALL_CONNECTED : <EOL> self . helloTimer = reactor . callLater ( <NUM_LIT> , self . helloTimerExpired ) <EOL> elif self . state in ( CALL_ABORT_TIMEOUT_PENDING , CALL_ABORT_PENDING , <EOL> CALL_DISCONNECT_ACK_PENDING , CALL_DISCONNECT_TIMEOUT_PENDING ) : <EOL> return <EOL> self . abort ( ATTRIB_STATUS_UNACCEPTED_FRAME_RECEIVED ) <EOL> def helloTimerExpired ( self , close = False ) : <EOL> if self . state == SERVER_CALL_DISCONNECTED : <EOL> self . transport . loseConnection ( ) <EOL> elif close : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> self . abort ( ATTRIB_STATUS_NEGOTIATION_TIMEOUT ) <EOL> else : <EOL> logging . info ( '<STR_LIT>' ) <EOL> echo = SSTPControlPacket ( SSTP_MSG_ECHO_REQUEST ) <EOL> echo . writeTo ( self . transport . write ) <EOL> self . helloTimer = reactor . callLater ( <NUM_LIT> , self . helloTimerExpired , True ) <EOL> def addRetryCounterOrAbrot ( self ) : <EOL> self . retryCounter += <NUM_LIT:1> <EOL> if self . retryCounter > <NUM_LIT:3> : <EOL> self . abort ( ATTRIB_STATUS_RETRY_COUNT_EXCEEDED ) <EOL> def abort ( self , status = None ) : <EOL> if status is None : <EOL> logging . warn ( '<STR_LIT>' ) <EOL> else : <EOL> logging . warn ( '<STR_LIT>' % ord ( status [ - <NUM_LIT:1> ] ) ) <EOL> self . state = CALL_DISCONNECT_IN_PROGRESS_1 <EOL> msg = SSTPControlPacket ( SSTP_MSG_CALL_ABORT ) <EOL> if status is not None : <EOL> msg . attributes = [ ( SSTP_ATTRIB_STATUS_INFO , status ) ] <EOL> msg . writeTo ( self . transport . write ) <EOL> self . state = CALL_ABORT_PENDING <EOL> reactor . callLater ( <NUM_LIT:3> , self . transport . loseConnection ) <EOL> def writePPPControlFrame ( self , frame ) : <EOL> logging . debug ( '<STR_LIT>' % len ( frame ) ) <EOL> logging . log ( VERBOSE , hexdump ( frame ) ) <EOL> if self . state == SERVER_CALL_CONNECTED_PENDING or self . state == SERVER_CALL_CONNECTED : <EOL> packet = SSTPDataPacket ( frame ) <EOL> packet . writeTo ( self . transport . write ) <EOL> def writePPPDataFrame ( self , frame ) : <EOL> if __debug__ : <EOL> logging . debug ( '<STR_LIT>' % len ( frame ) ) <EOL> logging . log ( VERBOSE , hexdump ( frame ) ) <EOL> if self . state == SERVER_CALL_CONNECTED : <EOL> packet = SSTPDataPacket ( frame ) <EOL> packet . writeTo ( self . transport . write ) <EOL> def pppStoped ( self ) : <EOL> if ( self . state != SERVER_CONNECT_REQUEST_PENDING and <EOL> self . state != SERVER_CALL_CONNECTED_PENDING and <EOL> self . state != SERVER_CALL_CONNECTED ) : <EOL> self . transport . loseConnection ( ) <EOL> return <EOL> self . state = CALL_DISCONNECT_IN_PROGRESS_1 <EOL> msg = SSTPControlPacket ( SSTP_MSG_CALL_DISCONNECT ) <EOL> msg . attributes = [ ( SSTP_ATTRIB_NO_ERROR , ATTRIB_STATUS_NO_ERROR ) ] <EOL> msg . writeTo ( self . transport . write ) <EOL> self . state = CALL_DISCONNECT_ACK_PENDING <EOL> reactor . callLater ( <NUM_LIT:5> , self . transport . loseConnection ) <EOL> class SSTPProtocolFactory ( Factory ) : <EOL> protocol = SSTPProtocol <EOL> def __init__ ( self , pppd , pppdConfigFile , local , remotePool , certHash = None ) : <EOL> self . pppd = pppd <EOL> self . pppdConfigFile = pppdConfigFile <EOL> self . local = local <EOL> self . remotePool = remotePool <EOL> self . certHash = certHash </s>
