Пример #1
0
class Simulator(object):
    """Main simulator class"""
    def __init__(self, args):
        """Pass in args as dict. Include:
        startTime
        endTime
        resourceList
        attackerList
        defenderList
        dtCost
        prCost
        DEF - []
        ATT - []
        """
        # Initialize state variables
        self.params = {}
        self.params["startTime"] = args["startTime"]
        self.params["endTime"] = args["endTime"]
        self.params["currentTime"] = 0
        self.params["downTime"] = args["downTime"]
        self.params["resourceReports"] = {}
        self.params["downTime"] = args["downTime"]
        self.attackerList = []
        self.defenderList = []
        self.gameState = 1
        self.askAtt = True
        self.askDef = True
        self.simType = 1
        self.utilType = 'Logistic2P'
        self.attSwitch = True  # For NO-OP, may not use this
        self.defSwitch = True  # FOr NO-OP, may noy use this
        # token = "probe"  # Shift all these into inside the strategies
        self.debug = 0
        # Initialize the utility parameters
        self.initUtility(args)
        # Remove this before pushing to prod
        # debugging.refreshLog()

        # Initialize environment settings
        if (args["missRate"] != 0):
            self.missRate = args["missRate"]
            self.probeCountdown = -1
            # debugging.log("miss rate set as " + str(self.missRate))
        else:
            self.missRate = None
            # debugging.log("miss rate is None")

        if (args["falseRate"] != 0):
            self.falseRate = args["falseRate"]
            # debugging.log("Lambda is " + str(self.falseRate))
        else:
            self.falseRate = None
            # debugging.log("Lambda is None")

        # Set the agent strategies in these
        self.defStrategy = None
        self.attStrategy = None
        for k, v in args["defenderList"].iteritems():
            self.defStrategy = v
        for k, v in args["attackerList"].iteritems():
            self.attStrategy = v

        # Initialize the state manager and the resources
        self.stateManager = StateManager(**{
            "resourceList": args["ResourceList"],
            "alpha": args["alpha"]
        })
        self.params["resourceReports"] = self.stateManager.resourceReportList

        # Initialize the agents
        self.initAgents(args)

        # Initialize the event queue
        f = (self.params["endTime"], 0, -1)
        self.eventQueue = [f]

        if self.falseRate is not None:
            self.getFakeProbe()

    def initUtility(self, args):
        self.utilParams = {}
        self.utilParams["dtCost"] = args["dtCost"]
        self.utilParams["prCost"] = args["prCost"]
        #  self.utilParams["DEF"] = args["DEF"]
        #  self.utilParams["ATT"] = args["ATT"]
        self.utilParams["downTime"] = args["downTime"]

        self.utilParams["attControlSlope"] = args["attControlSlope"]
        self.utilParams["attControlShift"] = args["attControlShift"]
        self.utilParams["attDownSlope"] = args["attDownSlope"]
        self.utilParams["attDownShift"] = args["attDownShift"]
        self.utilParams["defControlSlope"] = args["defControlSlope"]
        self.utilParams["defControlShift"] = args["defControlShift"]
        self.utilParams["defDownSlope"] = args["defDownSlope"]
        self.utilParams["defDownShift"] = args["defDownShift"]

        #  Weights for the function
        self.utilParams["attControlWeight"] = args["attControlWeight"]
        self.utilParams["defControlWeight"] = args["defControlWeight"]
        self.utilParams["resources"] = args["resources"]

    def initAgents(self, args):
        #  We probably don't need a list of agents, since its two player
        for k, v in args["attackerList"].iteritems():
            d = {
                "name": k,
                "strategy": v,
                "resourceList": args["ResourceList"],
                "time": self.params["currentTime"],
                "alpha": args["alpha"]
            }
            self.attacker = agents.Attacker(**d)

        for k, v in args["defenderList"].iteritems():
            d = {
                "name": k,
                "strategy": v,
                "resourceList": args["ResourceList"],
                "time": self.params["currentTime"],
                "alpha": args["alpha"]
            }
            self.defender = agents.Defender(**d)

    def updateInformation(self):
        # Should update the ground truth information state
        # print "Updating information - " + str(self.params["currentTime"])
        # print "Queue is ",
        # print self.eventQueue
        self.stateManager.updateState(self.params["currentTime"])
        info = {}  # isnt required. Consider removing
        info = self.stateManager.resourceReportList

        self.params["resourceReports"] = self.stateManager.resourceReportList
        info["time"] = self.params["currentTime"]

    def askAttacker(self):
        # Will ask the attacker for the time of the next attack
        # The attacker will return a queue event just stating that
        # wake him when the time to act is upon us

        nextEvent = self.attacker.getActionTime(self.params["currentTime"])
        if (nextEvent is None):
            # print "next event is", nextEvent
            return
        self.eventQueue.append(nextEvent)
        self.sortEventQueue()
        if self.debug:
            print self.eventQueue

    def askDefender(self):
        # Analogous to askAttacker. Defined as different functions
        # for convenience in later additions.

        nextEvent = self.defender.getActionTime(self.params["currentTime"])
        if (nextEvent is None):
            # print "nextevent is ", nextEvent
            return
        self.eventQueue.append(nextEvent)
        self.sortEventQueue()
        if self.debug:
            print self.eventQueuea

    def getFakeProbe(self):
        #  Gets the next fake probe to be put
        nextTime = self.fakeProbe()
        resource = random.choice(self.stateManager.activeResources.keys())
        event = (self.params["currentTime"] + nextTime, resource, 3)
        self.eventQueue.append(event)
        self.sortEventQueue()
        # print self.eventQueue

    def sortEventQueue(self):
        self.eventQueue = sorted(self.eventQueue)

    def shuffleEvents(self):
        #  Is there the possibility of three things queued for the same time?
        #  Consider shuffling more things, there may be a bias
        if (self.eventQueue[1][0] == self.eventQueue[2][0]):
            temp = self.eventQueue[:3]
            random.shuffle(temp)
            self.eventQueue = temp + self.eventQueue[3:]
        else:
            temp = self.eventQueue[:2]
            random.shuffle(temp)
            self.eventQueue = temp + self.eventQueue[2:]
        # print self.eventQueue

    def executeAction(self):
        # The agent needs to be asked what action to execute depending on the
        # current knowledge state. Must also take care of other queue events
        # that include servers waking up, false probes, horizon end time and
        # others. The eventQueue must have tuples corresponding to
        # <time, action, id>
        # The update of state should be done right after the execution
        self.askAtt = False
        self.askDef = False

        #  Both the attacker and defender knowledge states should have the
        #  latest time accessible.

        if (self.eventQueue[0][0] > self.params["endTime"]):
            # This is never going to happen since the endtime is a queued event
            assert (False)
        else:
            # If one or more event is queued at the same time then shuffle them
            # randomly. There should be no bias for events in ties.
            if (len(self.eventQueue) > 2):
                if (self.eventQueue[0][0] == self.eventQueue[1][0]):
                    # print "Shuffling happening"
                    self.shuffleEvents()
            #  Pop the next event from the queue
            it = self.eventQueue.pop(0)
            self.params["currentTime"] = it[0]
            if (self.debug):
                print it
            #  Check who queued the event
            #  For the end of the horizon
            #  Both the attacker and defender knowledge states should have the
            #  latest time accessible.
            self.attacker.knowledge.updateTime(self.params["currentTime"])
            self.defender.knowledge.updateTime(self.params["currentTime"])
            if (it[2] == -1):
                self.gameState = 0
                # debugging.eventLog(it)
                if (self.debug):
                    print "Game ending"
                return 0
            #  For a server waking up
            elif (it[2] == 2):
                if (self.debug):
                    print it[1] + " is up and running"
                #  Update the server status in the state manager
                self.stateManager.activeResources[it[1]] =\
                    self.stateManager.inactiveResources[it[1]]
                del self.stateManager.inactiveResources[it[1]]
                self.stateManager.activeResources[it[1]].isWoken(
                    self.params["currentTime"], self.params["downTime"])
                #  The defender knowledge state should be updated
                self.defender.seeServerWake(self.params["currentTime"], it[1])
                self.askDef = True
                # debugging.eventLog(it, it[1])
            #  For an attacker action
            elif (it[2] == 0):
                resourceName = self.attacker.getAction()
                #  In case the server went down without his knowledge
                #  is the probe wasted or not?
                if self.debug:
                    print "Ground truth before probe: "
                    print self.stateManager.activeResources
                while (resourceName in self.stateManager.inactiveResources):
                    #  the server went down and the attacker didn't know
                    #  Update the attackers knowledge state
                    if (self.debug):
                        print resourceName,
                        print "This resource has been reimaged"
                    #  If the attacker knew from before  that this server
                    #  has been reimaged then dont see the reimage again
                    #  However, for now we assume that the attacker has no
                    #  knowledge about the downtime, hence he asumes that
                    #  the reimage happened now
                    self.attacker.seeReimage(resourceName,
                                             self.params["currentTime"])
                    self.askAtt = True
                    self.askDef = False  # No point asking the defender

                    resourceName = self.attacker.getAction()
                #  The attacker belief about all the resources should be
                #  set to active since he assuemes nothng about downtime
                self.attacker.knowledge.setActive()
                if (resourceName in self.stateManager.activeResources):
                    #  Check if an interim reimage happened before executing
                    #  the probe on the resource. First update the knowledge
                    #  state of the attacker
                    self.attacker.checkKnowledgeState(
                        resourceName, self.stateManager.
                        activeResources[resourceName].previouslyReimaged(),
                        self.params["currentTime"])
                    #  Then update the knowledge state of the defender, if
                    #  the defender sees the probes
                    if ((self.missRate is None) or not (self.missProbe())):
                        # print "Defender seeing probe"
                        self.defender.seeProbe(resourceName,
                                               self.params["currentTime"])
                    #  Then update the ground truth with a probe
                    self.stateManager.probe(resourceName,
                                            self.params["currentTime"])
                    #  until the fautly sensors are implemented we can use
                    #  assert here that the ks and ground truth are the same
                    #  Launch the attack
                    compromise = self.stateManager.attack(resourceName)
                    if compromise:
                        #  update the attacker ks in case attack succeeds
                        self.attacker.seeCompromise(resourceName)
                        # debugging.logCompromise(resourceName,
                        #                        self.params["currentTime"])
                    self.askDef = True
                    self.askAtt = True
                else:
                    #  In case a null action is seen do nothing. No need to ask
                    #  the defender since there's no change in his state
                    assert (resourceName is None)
                    self.askAtt = True
                    self.askDef = False
                # debugging.eventLog(it, resourceName)
            #  For a defender action
            elif (it[2] == 1):
                resourceName = self.defender.getAction()
                #  A defender will never reimage a server that is down
                #  Change the ground truth
                if (resourceName):
                    # print resourceName
                    assert (resourceName in self.stateManager.activeResources)
                    #  If the attacker loses control his state must be updated
                    if (self.stateManager.activeResources[resourceName].
                            getControl() == "ATT"):
                        self.attacker.seeReimage(resourceName,
                                                 self.params["currentTime"])
                        self.askAtt = True
                    self.defender.seeReimage(resourceName,
                                             self.params["currentTime"])
                    self.stateManager.reimage(resourceName,
                                              self.params["currentTime"])
                    #  Change from active resource to inactive
                    self.stateManager.inactiveResources[resourceName] =\
                        self.stateManager.activeResources[resourceName]
                    del self.stateManager.activeResources[resourceName]
                    assert (self.stateManager.inactiveResources[resourceName].
                            lastReimage == self.params["currentTime"])
                    #  Make sure the defender reigsters the change in his ks
                    self.askDef = True
                    #  Queue the wake up event
                    wakeTime = self.params["currentTime"] +\
                        self.params["downTime"]
                    self.eventQueue.append((wakeTime, resourceName, 2))
                    self.sortEventQueue()
                else:
                    #  No  action can be taken by the defender
                    assert (resourceName is None)
                    self.askDef = True
                    self.askAtt = False
            elif (it[2] == 3):
                #  Fake probe to be detected by the defender
                # debugging.log("Fake probe on " + it[1])
                resourceName = "Fake on" + it[1]
                self.defender.seeProbe(it[1], self.params["currentTime"])
                self.getFakeProbe()
                self.askDef = True
            # debugging.eventLog(it, resourceName)
        #  At the end of the execution the history should be saved?
        #  ground truth is already being updateda
        self.updateInformation()
        return 0

    def missProbe(self):
        #  Uniform sampling at the moment
        random.seed()
        rand = random.random()
        if rand < self.missRate:
            # debugging.log("Defender is missing this probe")
            return True
        else:
            # debugging.log("Defender will see this probe")
            return False

    def fakeProbe(self):
        # Should only be called when no fake probes queued
        for item in self.eventQueue:
            assert (item[2] != 3)

        nextTime = random.expovariate(self.falseRate)
        return nextTime

    def simulate(self):
        # Starts the simulation
        if self.simType == 1:
            while (self.gameState):
                self.updateInformation()
                # self.defender.debugKnowledge()
                if self.askAtt:
                    self.askAttacker()
                if self.askDef:
                    self.askDefender()
                self.executeAction()
                # debugging.printAgentKS(self.attacker, self.defender)
                # debugging.printTruth(self.stateManager.activeResources,
                #                       self.stateManager.inactiveResources)

        #  Use the recorded history to get the utility
        self.updateInformation()

        #  Set up the utility function
        u = Utility(self.utilParams)
        utilFunc = u.getUtility(self.utilType)
        payoff = utilFunc(self.stateManager.stateHistory)
        #  if self.debug:
        # pprint.pprint(self.stateManager.stateHistory)

        return payoff