Beispiel #1
0
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()
Beispiel #2
0
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")
Beispiel #3
0
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()
Beispiel #4
0
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)
Beispiel #5
0
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
Beispiel #7
0
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__())
Beispiel #8
0
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__())
Beispiel #9
0
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