예제 #1
0
    def __init__(self, playgroundAddress):
        self._address = playgroundAddress

        # ports and connections are interrelated but slightly different
        # a port is just an integer key mapped to a control object.
        # a connection is tied to the port.
        self._ports = {}
        self._connections = {}
        self._freePorts = self._freePortsGenerator()
        self._linkTx = PlaygroundSwitchTxProtocol(self, self.address())
예제 #2
0
class VNIC:
    _STARTING_SRC_PORT = 2000
    _MAX_PORT = (2**16) - 1

    def __init__(self, playgroundAddress):
        self._address = PlaygroundAddress.FromString(playgroundAddress)
        logger.info("{} just started up".format(self))

        # ports and connections are interrelated but slightly different
        # a port is just an integer key mapped to a control object.
        # a connection is tied to the port.
        self._ports = {}
        self._connections = {}
        self._dumps = set([])
        self._freePorts = self._freePortsGenerator()
        self._linkTx = None  #PlaygroundSwitchTxProtocol(self, self.address())
        self._connectedToNetwork = False
        self._promiscuousMode = None

    def _freePortsGenerator(self):
        while True:
            for i in range(self._STARTING_SRC_PORT, self._MAX_PORT):
                if i in self._ports: continue
                yield i

    def promiscuousLevel(self):
        if self._promiscuousMode == None: return 0
        return self._promiscuousMode

    def setPromiscuousLevel(self, level):
        """
        Setting level to 0 or None turns promiscuous mode off.
        Otherwise, start listening for more addresses than just your own.
        
        Level 0: Address Only (off)
        Level 1: x.y.z.*
        Level 2: x.y.*.*
        Level 3: x.*.*.*
        Level 4: *.*.*.*
        """
        if level == None or level < 0: level = 0
        if level > 4: level = 4
        if level != self._promiscuousMode:
            self._promiscuousMode = level
            self._updateRegisteredAddress()

    def _updateRegisteredAddress(self):
        if not self.connected(): return
        level = self._promiscuousMode
        listeningBlock = PlaygroundAddressBlock(*self._address.toParts())
        for i in range(level):
            listeningBlock.getParentBlock()
        self._linkTx.changeRegisteredAddress(str(listeningBlock))

    def address(self):
        return self._address

    def connected(self):
        return self._connectedToNetwork

    def switchConnectionFactory(self):
        if self._linkTx and self._linkTx.transport:
            self._linkTx.transport.close()
        self._linkTx = PlaygroundSwitchTxProtocol(self, self.address())
        return self._linkTx

    def controlConnectionFactory(self):
        logger.debug(
            "{} creating control protocol for new connection.".format(self))
        controlProtocol = VNICSocketControlProtocol(self)
        return controlProtocol

    ###
    # Switch Dmux routines
    ###

    def connectionMade(self):
        logger.info("{} connected to network".format(self))
        self._connectedToNetwork = True
        if self.promiscuousLevel():
            self._updateRegisteredAddress()

    def connectionLost(self):
        logging.info("{} lost connection network".format(self))
        self._connectedToNetwork = False
        self._linkTx = None

    def demux(self, source, sourcePort, destination, destinationPort, data):
        logger.debug(
            "{} received {} bytes of data from {}:{} for {}:{}".format(
                self, len(data), source, sourcePort, destination,
                destinationPort))
        for dumper in self._dumps:
            dumpPacket = WirePacket(source=source,
                                    sourcePort=sourcePort,
                                    destination=destination,
                                    destinationPort=destinationPort,
                                    data=data)
            dumper.transport.write(dumpPacket.__serialize__())

        remotePortKey = PortKey(source, sourcePort, destination,
                                destinationPort)

        # this portkey is backwards. The source is from the remote machine
        # but our ports have the remote machine being the destination.
        # So, invert:

        localPortKey = remotePortKey.inverseKey()

        # Check if the full port key is already in connections. If so, we're all done
        if localPortKey in self._connections:
            self._connections[localPortKey].write(data)
            return

        # If there's no port key in connections, check for listening port.
        listeningPort = localPortKey.sourcePort
        if listeningPort in self._ports and self._ports[
                listeningPort].isListener():
            # We have a new connection. Spawn.
            # use a controlled port so that if the listening port is closed,
            # all of the spawned ports are closed.
            self._connections[localPortKey] = ConnectionData(
                localPortKey, self._ports[listeningPort])
            self._connections[localPortKey].write(data)
            self._ports[listeningPort].spawnConnection(localPortKey)

        else:
            pass  # drop? Fail silently?

    ### End Dmux Methods ###

    def spawnConnection(self, portKey, protocol):
        self._connections[portKey].setProtocol(protocol)

    def createOutboundSocket(self, control, destination, destinationPort):
        port = next(self._freePorts)

        self._ports[port] = control

        portKey = PortKey(str(self._address), port, destination,
                          destinationPort)
        self._connections[portKey] = ConnectionData(portKey, control)
        control.spawnConnection(portKey)

        return port

    def createInboundSocket(self, control, requestedPort):
        if requestedPort in self._ports:
            # port already in use
            return None

        self._ports[requestedPort] = control
        return requestedPort

    def closeConnection(self, portKey):
        if portKey in self._connections:
            connData = self._connections[portKey]
            del self._connections[portKey]

            connData.close()

    def closePort(self, port):
        if port in self._ports:
            control = self._ports[port]
            del self._ports[port]
            control.close()

    def controlClosed(self, control):
        portKeys = self._controlChannels.get(control.controlProtocol(), [])
        for pk in portKeys:
            self.closePort(pk)

    def write(self, portKey, data):
        logger.debug("VNIC sending message for port key {}".format(portKey))
        if not self._linkTx or not self._linkTx.transport:
            return
        self._linkTx.write(portKey.source, portKey.sourcePort,
                           portKey.destination, portKey.destinationPort, data)

    def startDump(self, protocol):
        self._dumps.add(protocol)

    def stopDump(self, protocol):
        if protocol in self._dumps:
            self._dumps.remove(protocol)

    def __repr__(self):
        return "VNIC ({})".format(self._address)
예제 #3
0
 def switchConnectionFactory(self):
     if self._linkTx and self._linkTx.transport:
         self._linkTx.transport.close()
     self._linkTx = PlaygroundSwitchTxProtocol(self, self.address())
     return self._linkTx
예제 #4
0
class VNIC:
    _STARTING_SRC_PORT = 2000
    _MAX_PORT = (2**16) - 1

    def __init__(self, playgroundAddress):
        self._address = playgroundAddress

        # ports and connections are interrelated but slightly different
        # a port is just an integer key mapped to a control object.
        # a connection is tied to the port.
        self._ports = {}
        self._connections = {}
        self._freePorts = self._freePortsGenerator()
        self._linkTx = None  #PlaygroundSwitchTxProtocol(self, self.address())
        self._connectedToNetwork = False

    def _freePortsGenerator(self):
        while True:
            for i in range(self._STARTING_SRC_PORT, self._MAX_PORT):
                if i in self._ports: continue
                yield i

    def address(self):
        return self._address

    def connectedToNetwork(self):
        return self._connectedToNetwork

    def switchConnectionFactory(self):
        if self._linkTx and self._linkTx.transport:
            self._linkTx.transport.close()
        self._linkTx = PlaygroundSwitchTxProtocol(self, self.address())
        return self._linkTx

    def controlConnectionFactory(self):
        controlProtocol = VNICSocketControlProtocol(self)
        return controlProtocol

    ###
    # Switch Dmux routines
    ###

    def connected(self):
        # TODO: log connected to the switch
        self._connectedToNetwork = True

    def disconnected(self):
        self._connectedToNetwork = False
        self._linkTx = None

    def demux(self, source, sourcePort, destination, destinationPort, data):
        remotePortKey = PortKey(source, sourcePort, destination,
                                destinationPort)

        # this portkey is backwards. The source is from the remote machine
        # but our ports have the remote machine being the destination.
        # So, invert:

        localPortKey = remotePortKey.inverseKey()

        # Check if the full port key is already in connections. If so, we're all done
        if localPortKey in self._connections:
            self._connections[localPortKey].write(data)
            return

        # If there's no port key in connections, check for listening port.
        listeningPort = localPortKey.sourcePort
        if listeningPort in self._ports and self._ports[
                listeningPort].isListener():
            # We have a new connection. Spawn.
            # use a controlled port so that if the listening port is closed,
            # all of the spawned ports are closed.
            self._connections[localPortKey] = ConnectionData(
                localPortKey, self._ports[listeningPort])
            self._connections[localPortKey].write(data)
            self._ports[listeningPort].spawnConnection(localPortKey)

        else:
            pass  # drop? Fail silently?

    ### End Dmux Methods ###

    def spawnConnection(self, portKey, protocol):
        self._connections[portKey].setProtocol(protocol)

    def createOutboundSocket(self, control, destination, destinationPort):
        port = next(self._freePorts)

        self._ports[port] = control

        portKey = PortKey(self._address, port, destination, destinationPort)
        self._connections[portKey] = ConnectionData(portKey, control)
        control.spawnConnection(portKey)

        return port

    def createInboundSocket(self, control, requestedPort):
        if requestedPort in self._ports:
            # port already in use
            return None

        self._ports[requestedPort] = control
        return requestedPort

    def closeConnection(self, portKey):
        if portKey in self._connections:
            connData = self._connections[portKey]
            del self._connections[portKey]

            connData.close()

    def closePort(self, port):
        if port in self._ports:
            control = self._ports[port]
            del self._ports[port]
            control.close()

    def controlClosed(self, control):
        portKeys = self._controlChannels.get(control.controlProtocol(), [])
        for pk in portKeys:
            self.closePort(pk)

    def write(self, portKey, data):
        if not self._linkTx or not self._linkTx.transport:
            return
        self._linkTx.write(portKey.source, portKey.sourcePort,
                           portKey.destination, portKey.destinationPort, data)