Defining New Actions

It is simple to add a new packet-level action to Geneva.

Let us assume we are adding a new action, called “mytamper”, which simply sets the ipid field of a packet. Our action will take 1 packet and return 1 packet, and we’ll start by making it always set the IPID to 1.

We will subclasss the Action class, and specify an __init__ method and a run method.

In the __init__ method, we will specify that our action’s name is ‘mytamper’ and can run in both inbound and outbound. Then, in the run() method, we will use Geneva’s packet API to set the ipid field to 1 and simply return the packet.

from actions.action import Action

class MyTamperAction(Action):
    """
    Geneva action to set the IPID to 1.
    """
    # Controls frequency with which this action is chosen by the genetic algorithm
    # during mutation
    frequency = 0

    def __init__(self, environment_id=None):
        Action.__init__(self, "mytamper", "both")

    def run(self, packet, logger):
        """
        The mytamper action returns a modified packet as the left child.
        """
        logger.debug("  - Changing IPID field to 1")
        packet.set("IP", "ipid", 1)
        return packet, None

And that’s it! Now, we can specify this action in our normal strategy DNA: Geneva will discover it dynamically on startup, import it, and we can use it.

Adding Parameters

Let’s now assume we want to make our action take parameters. We will add two new methods: parse() and __str__(). We’ll start by adding a new instance variable self.ipid_value.

def __init__(self, environment_id=None, ipid_value=1):
    Action.__init__(self, "mytamper", "both")
    self.ipid_value = ipid_value

Next, we’ll add the __str__ method so when our action is printed in the strategy DNA, its components are too:

def __str__(self):
    """
    Returns a string representation.
    """
    s = Action.__str__(self)
    s += "{%g}" % self.ipid_value
    return s

Finally, we’ll add the parse() method so we can parse the value from a string strategy DNA to a live action.

def parse(self, string, logger):
    """
    Parses a string representation for this object.
    """
    try:
        if string:
            self.ipid_value = float(string)
    except ValueError:
        logger.exception("Cannot parse ipid_value %s" % string)
        return False

    return True

Putting it all together:

from actions.action import Action

class MyTamperAction(Action):
    """
    Geneva action to set the IPID to 1.
    """
    # Controls frequency with which this action is chosen by the genetic algorithm
    # during mutation
    frequency = 0

    def __init__(self, environment_id=None, ipid_value=1):
        Action.__init__(self, "mytamper", "both")
        self.ipid_value = ipid_value

    def run(self, packet, logger):
        """
        The mytamper action returns a modified packet as the left child.
        """
        logger.debug("  - Changing IPID field to 1")
        packet.set("IP", "ipid", 1)
        return packet, None

    def __str__(self):
        """
        Returns a string representation.
        """
        s = Action.__str__(self)
        s += "{%g}" % self.ipid_value
        return s

    def parse(self, string, logger):
        """
        Parses a string representation for this object.
        """
        try:
            if string:
                self.ipid_value = float(string)
        except ValueError:
            logger.exception("Cannot parse ipid_value %s" % string)
            return False

        return True

And we’re done! Now, we can write strategies like: [TCP:flags:PA]-mytamper{10}-|, and any TCP packet with the flags field set to PA will have its ipid field set to 10.