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())
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)
def switchConnectionFactory(self): if self._linkTx and self._linkTx.transport: self._linkTx.transport.close() self._linkTx = PlaygroundSwitchTxProtocol(self, self.address()) return self._linkTx
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)