class PEEPPacket(PacketType): DEFINITION_IDENTIFIER = 'PEEP.Packet' DEFINITION_VERSION = '1.0' FIELDS = [ ('Type', UINT8), ('SequenceNumber', UINT32({Optional: True})), ('Checksum', UINT16), ("Acknowledgement", UINT32({Optional: True})), ("Data", BUFFER({Optional: True})) ] SYN = Constant(intValue=0, strValue="SYN") SYN_ACK = Constant(intValue=1, strValue="SYN-ACK") ACK = Constant(intValue=2, strValue="ACK") RIP = Constant(intValue=3, strValue="RIP") RIP_ACK = Constant(intValue=4, strValue="RIP-ACK") RST = Constant(intValue=5, strValue="RST") DATA = Constant(intValue=6, strValue="DATA") PACKET_TYPES = [SYN, SYN_ACK, ACK, RIP, RIP_ACK, RST, DATA] def calculate_checksum(self): original_checksum = self.Checksum self.Checksum = 0 bytes = self.__serialize__() self.Checksum = original_checksum return zlib.adler32(bytes) & 0xffff def update_checksum(self): self.Checksum = self.calculate_checksum() def verify_checksum(self): return self.Checksum == self.calculate_checksum()
class ProtocolObservation: """ This class allows a given protocol to be observed (i.e., listeners can receive event notifications). When a protocol is observed, its methods are adapted to report events to listeners. A protocol can be un-adapted at any time. Some events have automatic consequences. For example, when connection_made is called, it automatically records the transport and assigns a new transport with an adapted write method. Similarly, when a protocol's connection_lost method is called, it is automatically removed from observation. To prevent duplicate modification, a protocol's adapter is saved. Attempts to create a new adapter are prevented and the existing adapter returned. """ OBSERVED_PROTOCOLS = {} EVENT_CONNECTION_MADE = Constant(intValue=0) EVENT_CONNECTION_LOST = Constant(intValue=1) EVENT_DATA_RECEIVED = Constant(intValue=2) EVENT_DATA_SENT = Constant(intValue=3) class ProtocolAdapter: def __init__(self, protocol): self.originalConnectionMade = protocol.connection_made self.originalConnectionLost = protocol.connection_lost self.originalDataReceived = protocol.data_received self.transport = None self.originalTransportWrite = None self.listeners = set([]) def transportData(self, protocol): self.transport = protocol.transport self.originalTransportWrite = protocol.transport.write protocol.transport.write = lambda *args, **kargs: ProtocolObservation.protocolEvent( protocol, self.originalTransportWrite, ProtocolObservation. EVENT_DATA_SENT, *args, **kargs) def restoreProtocol(self, protocol): protocol.connection_made = self.originalConnectionMade protocol.connection_lost = self.originalConnectionLost protocol.data_received = self.originalDataReceived if self.transport and self.originalTransportWrite: self.transport.write = self.originalTransportWrite self.transport = None self.originalTransportWrite = None self.originalConnectionLost = None self.originalConnectionMade = None self.originalDataReceived = None if protocol in ProtocolObservation.OBSERVED_PROTOCOLS: del ProtocolObservation.OBSERVED_PROTOCOLS[protocol] @classmethod def protocolEvent(cls, protocol, protocolMethod, event, *args, **kargs): r = protocolMethod(*args, **kargs) protocolData = cls.OBSERVED_PROTOCOLS.get(protocol, None) if not protocolData: return r for l in protocolData.listeners: l(protocol, event, r, args, kargs) if event == cls.EVENT_CONNECTION_MADE and protocol.transport: protocolData.transportData(protocol) if event == cls.EVENT_CONNECTION_LOST: protocolData.restoreProtocol(protocol) #del cls.PROTOCOL_LISTENERS[protocol] return r @classmethod def EnableProtocol(cls, protocol): if not protocol in cls.OBSERVED_PROTOCOLS: protocolData = cls.ProtocolAdapter(protocol) cls.OBSERVED_PROTOCOLS[protocol] = protocolData protocol.connection_made = lambda *args, **kargs: cls.protocolEvent( protocol, protocolData.originalConnectionMade, cls. EVENT_CONNECTION_MADE, *args, **kargs) protocol.connection_lost = lambda *args, **kargs: cls.protocolEvent( protocol, protocolData.originalConnectionLost, cls. EVENT_CONNECTION_LOST, *args, **kargs) protocol.data_received = lambda *args, **kargs: cls.protocolEvent( protocol, protocolData.originalDataReceived, cls. EVENT_DATA_RECEIVED, *args, **kargs) return protocol @classmethod def Listen(cls, protocol, listener): cls.EnableProtocol(protocol) cls.OBSERVED_PROTOCOLS[protocol].listeners.add(listener) @classmethod def StopListening(cls, protocol, listener): adapter = cls.OBSERVED_PROTOCOLS.get(protocol, None) if not adapter or not listener in adapter.listeners: return adapter.listeners.remove(listener) if not adapter.listeners: adapter.restoreProtocol(protocol) @classmethod def EnableProtocolClass(cls, protocolClass): raise Exception("Not yet implemented")
class PNMSDevice(metaclass=PNMSDeviceLoader): CONFIG_TRUE = "true" CONFIG_FALSE = "false" CONFIG_OPTION_AUTO = "auto_enable" """ Sub classes that need access to the Connection section or Routing section need to override these values """ CanConnectTo = [] CanRoute = False STATUS_DISABLED = Constant(strValue="Disabled", boolValue=False) STATUS_WAITING_FOR_DEPENDENCIES = Constant(strValue="Waiting", boolValue=False) STATUS_ABNORMAL_SHUTDOWN = Constant(strValue="Abnormal Shutdown", boolValue=False) STATUS_ENABLED = Constant(strValue="Enabled", boolValue=True) REGISTER_DEVICE_TYPE_NAME = None # All abstract classes should leave this none. All concrete classes must specify. @classmethod def initialize_help(cls): return "{name} [ARGS]".format(name=cls.REGISTER_DEVICE_TYPE_NAME) def __init__(self, deviceName): self._pnms = None self._config = None self._name = deviceName self._deviceDependencies = set([]) # the status is the current status self._enableStatus = self.STATUS_DISABLED # the toggle is if there has been a request to go from one state to the other self._enableToggle = False def _cleanupFiles(self): if not self._enableStatus: runFiles = self._getDeviceRunFiles() for file in runFiles: if os.path.exists(file): os.unlink(file) def _reloadRuntimeData(self): pass def installToNetwork(self, pnms, mySection): self._pnms = pnms self._config = mySection self._reloadRuntimeData() # call self.enabled to correctly set enableStatus # cannot call in constructor, requires self._pnms self._runEnableStatusStateMachine() def networkManager(self): return self._pnms def _sanitizeVerb(self, verb): return verb.strip().lower() def name(self): return self._name def dependenciesEnabled(self): for device in self._deviceDependencies: if not device.enabled(): return False return True def isAutoEnabled(self): return self._config.get(self.CONFIG_OPTION_AUTO, self.CONFIG_FALSE) == self.CONFIG_TRUE def pnmsAlert(self, device, alert, alertArgs): if device in self._deviceDependencies: if alert == device.enabled: self._runEnableStatusStateMachine() def initialize(self, args): pass def destroy(self): pass def enable(self): if not self.enabled(): self._enableToggle = True self._runEnableStatusStateMachine() def disable(self): if self.enabled(): self._enableToggle = True self._runEnableStatusStateMachine() def enabled(self): self._cleanupFiles() return self._enableStatus def getPid(self): statusFile, pidFile, lockFile = self._getDeviceRunFiles() if os.path.exists(pidFile): with open(pidFile) as f: return int(f.read().strip()) return None def config(self, verb, args): pass def query(self, verb, args): return None def _getDeviceRunFiles(self): statusFile = os.path.join(self._pnms.location(), "device_{}.status".format(self.name())) pidFile = os.path.join(self._pnms.location(), "device_{}.pid".format(self.name())) lockFile = os.path.join(self._pnms.location(), "device_{}.pid.lock".format(self.name())) return statusFile, pidFile, lockFile def _running(self): for requiredFile in self._getDeviceRunFiles(): if not os.path.exists(requiredFile): return False pid = self.getPid() return pid and isPidAlive(pid) def _runEnableStatusStateMachine(self): newStatus = self._enableStatus # TODO: I wrote this function in a 'haze' thinkin the manager keeps running. # but, of course, it shuts down after run. There's going to be # no callback. Well, I'm leaving this code in. Because, it may # be that in the future I have a call-back system that works. # but for now, let's try to activate everything. if not self._enableStatus and self._enableToggle: for device in self._deviceDependencies: if not device.enabled(): device.enable() if self._enableStatus in [ self.STATUS_DISABLED, self.STATUS_ABNORMAL_SHUTDOWN ]: if self._running(): # We might have gotten here because of a restart # or a toggle. if self.dependenciesEnabled(): newStatus = self.STATUS_ENABLED else: # oops. A dependency has shut down. # Assume this device was supposed to be enabled. self._shutdown() newStatus = self.STATUS_WAITING_FOR_DEPENDENCIES elif self._enableToggle: if self.dependenciesEnabled(): self._launch() if self._running(): newStatus = self.STATUS_ENABLED else: newStatus = self.STATUS_ABNORMAL_SHUTDOWN else: newStatus = self.STATUS_DISABLED elif self._enableStatus == self.STATUS_WAITING_FOR_DEPENDENCIES: if self._enableToggle: # we were trying to turn on, were waiting for deps, but now stop newStatus = self.STATUS_DISABLED elif self.dependenciesEnabled(): self._launch() if self._running(): newStatus = self.STATUS_ENABLED else: newStatus = self.STATUS_ABNORMAL_SHUTDOWN else: newStatus = self.STATUS_WAITING_FOR_DEPENDENCIES elif self._enableStatus == self.STATUS_ENABLED: if self._enableToggle: self._shutdown() newStatus = self.STATUS_DISABLED elif not self._running(): newStatus = self.STATUS_DISABLED elif not self.dependenciesEnabled(): self._shutdown() newStatus = self.STATUS_WAITING_FOR_DEPENDENCIES else: newStatus = self.STATUS_ENABLED alert = (self._enableStatus != newStatus) self._enableStatus = newStatus self._enableToggle = False self._pnms.postAlert(self.enable, self._enableStatus) def _shutdown(self, timeout=5): pid = self.getPid() if pid: os.kill(pid, signal.SIGTERM) sleepCount = timeout while isPidAlive(pid) and sleepCount > 0: time.sleep(1) sleepCount = sleepCount - 1 if isPidAlive(pid): raise Exception( "Could not shut down device {}. (pid={})".format( self.name(), pid)) for file in self._getDeviceRunFiles(): if os.path.exists(file): os.unlink(file) def _launch(self, timeout=30): pass def _waitUntilRunning(self, timeout=30): sleepCount = timeout while not self._running() and sleepCount > 0: time.sleep(1) sleepCount = sleepCount - 1 return self._running()
class SocketControl: SOCKET_TYPE_CONNECT = Constant(strValue="Outbound Connection Socket") SOCKET_TYPE_LISTEN = Constant(strValue="Inbound Listening Socket") def __init__(self, connectionId, socketType, callbackAddr, callbackPort, controlProtocol): self._connectionId = connectionId self._type = socketType self._port = None self._callbackAddr = callbackAddr self._callbackPort = callbackPort self._controlProtocol = controlProtocol self._spawnedConnectionKeys = set([]) self._closed = False def connectionId(self): return self._connectionId def setPort(self, port): self._port = port def closed(self): return self._closed def close(self): """ Close down the whole socket including all spawned connections. """ if not self._closed: self._closed = True portKeys = self._spawnedConnectionKeys self._spawnedConnectionKeys = set([]) for portKey in portKeys: self.device().closeConnection(portKey) (self._port != None) and self.device().closePort(self._port) def closeSpawnedConnection(self, portKey): """ Only close a single spawned connection. However, if this is an outbound socket, will close everything. """ if self._type == self.SOCKET_TYPE_CONNECT: # outbound connections only have one connection per socket self.close() else: # inbound connections can have many. Just close this one. self.device().closeConnection(portKey) def spawnedConnectionClosed(self, portKey): """ This is a callback if the spawned connection closes. This can be circular (we close a connection that then calls us back) so it is important to check """ if portKey in self._spawnedConnectionKeys: self._spawnedConnectionKeys.remove(portKey) if not self._closed and self._type == self.SOCKET_TYPE_CONNECT: # outbound connections only have one connection per socket self.close() def device(self): return self._controlProtocol.device() def controlProtocol(self): return self._controlProtocol def isListener(self): return self._type == self.SOCKET_TYPE_LISTEN def spawnConnection(self, portIndex): if self._type == self.SOCKET_TYPE_CONNECT and len(self._spawnedConnectionKeys) != 0: raise Exception("Duplicate Connection on Outbound Connect!") logger.debug("{} spwaning connection on portkey {}. Callback={}:{}".format(self.device(), portIndex, self._callbackAddr, self._callbackPort)) # create the reverse connection to complete opening the socket loop = asyncio.get_event_loop() coro = loop.create_connection(lambda: ReverseOutboundSocketProtocol(self, portIndex), self._callbackAddr, self._callbackPort) futureConnection = asyncio.get_event_loop().create_task(coro) futureConnection.add_done_callback(self._spawnFinished) def _spawnFinished(self, futureConnection): logger.debug("{} spawn completed. {}".format(self.device(), futureConnection)) if futureConnection.exception() != None: # Opening the reverse connection failed. Shut down. # this might be a little harsh. It could close many other # connections. self.close() else: transport, protocol = futureConnection.result() self._spawnedConnectionKeys.add(protocol._portKey) self.device().spawnConnection(protocol._portKey, protocol) reverseConnectionLocalPort = transport.get_extra_info("sockname")[1] self._controlProtocol.sendConnectionSpawned(self._connectionId, reverseConnectionLocalPort, protocol._portKey)
class VNICSocketControlProtocol(Protocol): ERROR_UNKNOWN = Constant(strValue="An Unknown Error", intValue=255) ERROR_BUSY = Constant(strValue="Port is not available", intValue=1) def __init__(self, vnic): self._vnic = vnic self._deserializer = PacketType.Deserializer() self._control = {} self.transport = None def controlLost(self, controlId): if controlId in self._control: control = self._control[controlId] control.close() del self._control[controlId] def device(self): return self._vnic def close(self): self.transport and self.transport.close() def connection_made(self, transport): logger.debug("VNIC socket control spawn {}".format(self)) self.transport = transport def connection_lost(self, reason=None): logger.debug("VNIC connection_lost {} for reason {}".format(self, reason)) for controlId in self._control: control = self._control[controlId] try: control.close() except: pass self._control = {} self.transport = None def data_received(self, data): self._deserializer.update(data) for controlPacket in self._deserializer.nextPackets(): if isinstance(controlPacket, VNICSocketOpenPacket): logger.info("{} received socket open operation.".format(self._vnic)) self.socketOpenReceived(controlPacket) elif isinstance(controlPacket, VNICSocketClosePacket): logger.info("{} received socket close {} operation".format(self._vnic, controlPacket.ConnectionId)) self.controlLost(controlPacket.ConnectionId) elif isinstance(controlPacket, WirePacket): logger.debug("{} received raw wire for dump mode connection.".format(self._vnic)) outboundKey = PortKey(controlPacket.source, controlPacket.sourcePort, controlPacket.destination, controlPacket.destinationPort) self._vnic.write(outboundKey, controlPacket.data) elif isinstance(controlPacket, VNICPromiscuousLevelPacket): logger.info("{} received promiscuous control packet.".format(self._vnic)) try: logger.info("{} setting prom. mode to {}".format(self._vnic, controlPacket.set)) if controlPacket.set != controlPacket.UNSET: self._vnic.setPromiscuousLevel(controlPacket.set) controlPacket.set = controlPacket.UNSET controlPacket.get = self._vnic.promiscuousLevel() logger.info("{} returning level {}".format(self, controlPacket.get)) self.transport.write(controlPacket.__serialize__()) except Exception as error: logger.error("{} got error {}".format(self._vnic, error)) #elif isinstance(controlPacket, VNICSocketStatusPacket): # self.socketStatusReceived(controlPacket) #elif isinstance(controlPacket, VNICSocketClosePacket): # self.socketCloseReceived(controlPacket) else: logger.info("{} received unknown packet {}".format(self._vnic, controlPacket)) def socketOpenReceived(self, openSocketPacket): resp = VNICSocketOpenResponsePacket(ConnectionId=openSocketPacket.ConnectionId) if openSocketPacket.ConnectionId in self._control: resp.port = 0 resp.errorCode = int(self.ERROR_BUSY) resp.errorMessage = "Connection ID Already in Use" elif openSocketPacket.isConnectType(): control = SocketControl(openSocketPacket.ConnectionId, SocketControl.SOCKET_TYPE_CONNECT, openSocketPacket.callbackAddress, openSocketPacket.callbackPort, self) self._control[openSocketPacket.ConnectionId] = control connectData = openSocketPacket.connectData port = self._vnic.createOutboundSocket(control, connectData.destination, connectData.destinationPort) if port != None: resp.port = port control.setPort(port) else: resp.port = 0 resp.errorCode = int(self.ERROR_UNKNOWN) resp.errorMessage = str(self.ERROR_UNKNOWN) elif openSocketPacket.isListenType(): control = SocketControl(openSocketPacket.ConnectionId, SocketControl.SOCKET_TYPE_LISTEN, openSocketPacket.callbackAddress, openSocketPacket.callbackPort, self) self._control[openSocketPacket.ConnectionId] = control listenData = openSocketPacket.listenData port = self._vnic.createInboundSocket(control, listenData.sourcePort) if port == listenData.sourcePort: resp.port = port control.setPort(port) else: resp.port = 0 resp.errorCode = int(self.ERROR_BUSY) resp.errorMessage = str(self.ERROR_BUSY) else: pass # error self.transport.write(resp.__serialize__()) def sendConnectionSpawned(self, connectionId, spawnTcpPort, portKey): #logger.info("Spawning new connection for listener with resvId %d for %s %d on local TCP port %d" % # (resvId, dstAddr, dstPort, connPort)) eventPacket = VNICConnectionSpawnedPacket(ConnectionId=connectionId, spawnTcpPort = spawnTcpPort, source = portKey.source, sourcePort = portKey.sourcePort, destination = portKey.destination, destinationPort = portKey.destinationPort) self.transport.write(eventPacket.__serialize__())
class PacketFieldType: UNSET = Constant(strValue="Unset Packet Field", boolValue=False) @classmethod def GetAttribute(cls, field, attr, default=None): """ This class method is designed to get the attribute from a field, whether the field is an instance of the class itself. If the class itself, there are not attributes, and it returns none (or the default) """ if isinstance(field, PacketFieldType): return field._getAttribute(attr, default) else: return default @classmethod def CreateInstance(cls, field): """ This class method is designed to create an instance of the field, whether the field is an instance or the class itself. If the class itself, call the class method _CreateInstance, which can be overridden by subclasses. If the instance, return the instance's clone method() """ if isinstance(field, PacketFieldType): return field.clone() else: return field._CreateInstance() @classmethod def _CreateInstance(cls): return cls() def __init__(self, attributes=None): self._attributes = {} self._validators = set([]) if attributes != None: self._attributes.update(attributes) for attr in attributes: # Every attribute can have "base attributes" that are analogous to "base classes" # When an attribute is registered, it also registers for base attributes that are # unset. In this way, when client code can query for a base attribute that was # set by a more specific attribute. baseAttributes = attr.baseAttributes() while baseAttributes: baseAttr = baseAttributes.pop(0) if baseAttr not in self._attributes: self._attributes[ baseAttr] = attr.translateAttributeValue( baseAttr, self._attributes[attr]) baseAttributes += baseAttr.baseAttributes() if isinstance(attr, Validator): self._validators.add(attr) self._data = self.UNSET def setData(self, data): if data == self.UNSET: self._data = data return self._setTypedData(data) for validator in self._validators: attrValue = self._attributes[validator] if not validator.validate(self._data, attrValue): raise ValueError( "Cannot set field to {} for type with attribute {}={}". format(data, validator, attrValue)) def _setTypedData(self, data): """ This function is to be generally overridden by subclasses that need to check the data for typing. """ self._data = data def data(self): return self._data def _getAttribute(self, attr, default=None): return self._attributes.get(attr, default) def __call__(self, newAttributes=None): cloneAttributes = {} cloneAttributes.update(self._attributes) if newAttributes: cloneAttributes.update(newAttributes) cls = self.__class__ instance = cls(cloneAttributes) return instance
class VNICSocketControlProtocol(Protocol): MODE_NONE = Constant(strValue="Startup Mode") MODE_OPENING = Constant(strValue="Socket Opening") MODE_CONNECTED = Constant(strValue="Outbound Socket Connected") MODE_LISTENING = Constant(strValue="Outbound Socket Listening") MODE_CLOSING = Constant(strValue="Socket Closing") MODE_DUMP = Constant(strValue="Special Mode Dump") ERROR_UNKNOWN = Constant(strValue="An Unknown Error", intValue=255) ERROR_BUSY = Constant(strValue="Port is not available", intValue=1) def __init__(self, vnic): self._vnic = vnic self._state = self.MODE_OPENING self._deserializer = PacketType.Deserializer() self._control = None self._mode = self.MODE_NONE self.transport = None def device(self): return self._vnic def close(self): self.transport and self.transport.close() def connection_made(self, transport): self.transport = transport def connection_lost(self, reason=None): if self._mode == self.MODE_DUMP: self._vnic.stopDump(self) elif self._control: self._control.close() self.transport = None def data_received(self, data): self._deserializer.update(data) for controlPacket in self._deserializer.nextPackets(): if isinstance(controlPacket, VNICSocketOpenPacket): logger.info("{} received socket open operation.".format( self._vnic)) self.socketOpenReceived(controlPacket) elif isinstance(controlPacket, VNICStartDumpPacket): logger.info("{} received start dump operation.".format( self._vnic)) self._mode = self.MODE_DUMP self._vnic.startDump(self) elif isinstance(controlPacket, WirePacket) and self._mode == self.MODE_DUMP: logger.debug( "{} received raw wire for dump mode connection.".format( self._vnic)) outboundKey = PortKey(controlPacket.source, controlPacket.sourcePort, controlPacket.destination, controlPacket.destinationPort) self._vnic.write(outboundKey, controlPacket.data) elif isinstance(controlPacket, VNICPromiscuousLevelPacket): logger.info("{} received promiscuous control packet.".format( self._vnic)) try: logger.info("{} setting prom. mode to {}".format( self._vnic, controlPacket.set)) if controlPacket.set != controlPacket.UNSET: self._vnic.setPromiscuousLevel(controlPacket.set) controlPacket.set = controlPacket.UNSET controlPacket.get = self._vnic.promiscuousLevel() logger.info("{} returning level {}".format( self, controlPacket.get)) self.transport.write(controlPacket.__serialize__()) except Exception as error: logger.error("{} got error {}".format(self._vnic, error)) #elif isinstance(controlPacket, VNICSocketStatusPacket): # self.socketStatusReceived(controlPacket) #elif isinstance(controlPacket, VNICSocketClosePacket): # self.socketCloseReceived(controlPacket) else: logger.info("{} received unknown packet {}".format( self._vnic, controlPacket)) def socketOpenReceived(self, openSocketPacket): resp = VNICSocketOpenResponsePacket() if self._state != self.MODE_OPENING: resp.errorCode = resp.GENERAL_ERROR resp.errorMessage = "Socket Already Open" elif openSocketPacket.isConnectType(): self._control = SocketControl(SocketControl.SOCKET_TYPE_CONNECT, openSocketPacket.callbackAddress, openSocketPacket.callbackPort, self) connectData = openSocketPacket.connectData port = self._vnic.createOutboundSocket(self._control, connectData.destination, connectData.destinationPort) if port != None: resp.port = port self._control.setPort(port) else: resp.port = 0 resp.errorCode = int(self.ERROR_UNKNOWN) resp.errorMessage = str(self.ERROR_UNKNOWN) elif openSocketPacket.isListenType(): self._control = SocketControl(SocketControl.SOCKET_TYPE_LISTEN, openSocketPacket.callbackAddress, openSocketPacket.callbackPort, self) listenData = openSocketPacket.listenData port = self._vnic.createInboundSocket(self._control, listenData.sourcePort) if port == listenData.sourcePort: resp.port = port self._control.setPort(port) else: resp.port = 0 resp.errorCode = int(ERROR_BUSY) resp.errorMessage = str(ERROR_BUSY) else: pass # error self.transport.write(resp.__serialize__()) def sendConnectionSpawned(self, spawnTcpPort, portKey): #logger.info("Spawning new connection for listener with resvId %d for %s %d on local TCP port %d" % # (resvId, dstAddr, dstPort, connPort)) eventPacket = VNICConnectionSpawnedPacket( spawnTcpPort=spawnTcpPort, source=portKey.source, sourcePort=portKey.sourcePort, destination=portKey.destination, destinationPort=portKey.destinationPort) self.transport.write(eventPacket.__serialize__())
class VNICSocketControlProtocol(Protocol): MODE_OPENING = Constant(strValue="Socket Opening") MODE_CONNECTED = Constant(strValue="Outbound Socket Connected") MODE_LISTENING = Constant(strValue="Outbound Socket Listening") MODE_CLOSING = Constant(strValue="Socket Closing") ERROR_UNKNOWN = Constant(strValue="An Unknown Error", intValue=255) ERROR_BUSY = Constant(strValue="Port is not available", intValue=1) def __init__(self, vnic): self._vnic = vnic self._state = self.MODE_OPENING self._deserializer = VNICSocketOpenPacket.Deserializer() self._control = None self.transport = None def device(self): return self._vnic def close(self): self.transport and self.transport.close() def connection_made(self, transport): self.transport = transport def connection_lost(self, reason=None): self._control and self._control.close() def dataReceived(self, data): self._deserializer.update(data) for controlPacket in self._deserializer.nextPackets(): if isinstance(controlPacket, VNICSocketOpenPacket): self.socketOpenReceived(controlPacket) #elif isinstance(controlPacket, VNICSocketStatusPacket): # self.socketStatusReceived(controlPacket) #elif isinstance(controlPacket, VNICSocketClosePacket): # self.socketCloseReceived(controlPacket) #else: # self.unknownPacketReceived(controlPacket) def socketOpenReceived(self, openSocketPacket): resp = VNICSocketOpenResponsePacket() if self._state != self.MODE_OPENING: resp.errorCode = resp.GENERAL_ERROR resp.errorMessage = "Socket Already Open" elif openSocketPacket.isConnectType(): self._control = SocketControl(SocketControl.SOCKET_TYPE_CONNECT, openSocketPacket.callbackAddress, openSocketPacket.callbackPort, self) connectData = openSocketPacket.connectData port = self._vnic.createOutboundSocket(self._control, connectData.destination, connectData.destinationPort) if port != None: resp.port = port self._control.setPort(port) else: resp.port = 0 resp.errorCode = int(self.ERROR_UNKNOWN) resp.errorMessage = str(self.ERROR_UNKNOWN) elif openSocketPacket.isListenType(): self._control = SocketControl(SocketControl.SOCKET_TYPE_LISTEN, openSocketPacket.callbackAddress, openSocketPacket.callbackPort, self) listenData = openSocketPacket.listenData port = self._vnic.createInboundSocket(self._control, listenData.sourcePort) if port == listenData.sourcePort: resp.port = port self._control.setPort(port) else: resp.port = 0 resp.errorCode = int(ERROR_BUSY) resp.errorMessage = str(ERROR_BUSY) else: pass # error self.transport.write(resp.__serialize__()) def sendConnectionSpawned(self, spawnTcpPort, portKey): #logger.info("Spawning new connection for listener with resvId %d for %s %d on local TCP port %d" % # (resvId, dstAddr, dstPort, connPort)) eventPacket = VNICConnectionSpawnedPacket(spawnTcpPort = spawnTcpPort, source = portKey.source, sourcePort = portKey.sourcePort, destination = portKey.destination, destinationPort = portKey.destinationPort) self.transport.write(eventPacket.__serialize__())
class PEEPPacket(PacketType): DEFINITION_IDENTIFIER = 'peep.packet' DEFINITION_VERSION = '1.2' FIELDS = [('Type', UINT8), ('SequenceNumber', UINT32({Optional: True})), ('Checksum', UINT16), ("Acknowledgement", UINT32({Optional: True})), ("Data", BUFFER({Optional: True}))] # Type SYN = Constant(intValue=0, strValue='SYN') SYN_ACK = Constant(intValue=1, strValue='SYN-ACK') ACK = Constant(intValue=2, strValue='ACK') RIP = Constant(intValue=3, strValue='RIP') RIP_ACK = Constant(intValue=4, strValue='RIP-ACK') DATA = Constant(intValue=5, strValue='DATA') PACKET_TYPES = [SYN, SYN_ACK, ACK, RIP_ACK, DATA] def updateSeqAcknumber(self, seq, ack): self.SequenceNumber = seq self.Acknowledgement = ack def calculateChecksum(self): original_checksum = self.Checksum self.Checksum = 0 bytes = self.__serialize__() self.Checksum = original_checksum return zlib.adler32(bytes) & 0xffff def updateChecksum(self): self.Checksum = self.calculateChecksum() def verifyChecksum(self): return self.Checksum == self.calculateChecksum() def __lt__(self, other): return self.SequenceNumber < other.SequenceNumber @classmethod def Create_SYN(cls): seq_number = random.randint(0, 2**16) packet = cls(Type=cls.SYN, SequenceNumber=seq_number, Checksum=0) packet.updateChecksum() return packet @classmethod def Create_SYN_ACK(cls, client_seq_num): seq_number = random.randint(0, 2**16) packet = cls(Type=cls.SYN_ACK, SequenceNumber=seq_number, Checksum=0, Acknowledgement=client_seq_num + 1) packet.updateChecksum() return packet @classmethod def Create_handshake_ACK(cls, server_seq_num, client_seq_num): packet = cls(Type=cls.ACK, SequenceNumber=client_seq_num + 1, Checksum=0, Acknowledgement=server_seq_num + 1) packet.updateChecksum() return packet @classmethod def Create_packet_ACK(cls, expected_seq_number): packet = cls(Type=cls.ACK, Checksum=0, Acknowledgement=expected_seq_number) packet.updateChecksum() return packet @classmethod def Create_RIP(cls, expected_seq_number): packet = cls(Type=cls.RIP, SequenceNumber=expected_seq_number, Checksum=0) packet.updateChecksum() return packet @classmethod def Create_RIP_ACK(cls, expected_seq_num, sender_seq_num): packet = cls(Type=cls.RIP_ACK, SequenceNumber=expected_seq_num, Checksum=0, Acknowledgement=sender_seq_num + 1) packet.updateChecksum() return packet @classmethod def Create_DATA(cls, seq_number, data, size_for_previous_data): packet = cls(Type=cls.DATA, SequenceNumber=seq_number + size_for_previous_data, Checksum=0, Data=data) packet.updateChecksum() return packet @classmethod def makeSynPacket(cls, seq): pkt = cls() pkt.Type = cls.TYPE_SYN pkt.SequenceNumber = seq pkt.updateChecksum() return pkt @classmethod def makeSynAckPacket(cls, seq, ack): pkt = cls() pkt.Type = cls.TYPE_SYN_ACK pkt.SequenceNumber = seq pkt.Acknowledgement = ack pkt.updateChecksum() return pkt @classmethod def makeAckPacket(cls, seq, ack): pkt = cls() pkt.Type = cls.TYPE_ACK if seq: pkt.SequenceNumber = seq pkt.Acknowledgement = ack pkt.updateChecksum() return pkt @classmethod def makeRipPacket(cls, seq, ack): pkt = cls() pkt.Type = cls.TYPE_RIP pkt.SequenceNumber = seq pkt.Acknowledgement = ack pkt.updateChecksum() return pkt @classmethod def makeRipAckPacket(cls, ack): pkt = cls() pkt.Type = cls.TYPE_RIP_ACK pkt.Acknowledgement = ack pkt.updateChecksum() return pkt @classmethod def makeDataPacket(cls, seq, data): pkt = cls() pkt.Type = cls.TYPE_DATA pkt.SequenceNumber = seq pkt.Data = data pkt.updateChecksum() return pkt