1
  1. I am attempting to insert GRErouting layer in between GRE and IP using Scapy. The pcap I am reading contains a single packet stacked as follows: Ethernet/IPv4/GRE/IPv4/ICMP. What I see is that getLayer returns the current layer + its payload, which may include other layers, and that's not good for me. I would like to only get the current layer. When I do getLayer for each layer, and then write the entire array I get a strange pcap because of the additional payload that each layer has over it.
  2. I am also not able to use a simple 'print' to output any data to console. I understand this is because Scapy adds the logging module, and suppresses system logging, but I'd like to know how to undo that and be able to use the 'print' statement.

    import os
    import sys
    import logging
    logging.basicConfig()
    logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
    from scapy.all import PcapReader, PcapWriter, fuzz, Packet
    from scapy.layers.l2 import GRE, GRErouting
    from scapy.layers.inet import IP
    logging.getLogger("scapy.runtime").setLevel(logging.DEBUG)
    logging.getLogger().setLevel(logging.DEBUG)
    
    
    def foo(in_filename, out_filename):
        f = PcapReader(in_filename)
        o = PcapWriter(out_filename)
    
        p = f.read_packet()
    
        while p:
            layers = []
            counter = 0
            while True:
                layer = p.getlayer(counter)
                if (layer != None):
                    layers.append(layer)
    
                    if (type(layer) is IP):
                        del layer.chksum
                    if (type(layer) is GRE):
                        logging.getLogger().debug("there is a GRE layer") 
                        layer.routing_present = 1
                        gr = GRErouting()
                        fuzz(gr)
                        layers.append(gr)
                        del layer.chksum
                else:
                    break
                counter += 1
            logging.getLogger().debug("Layers are: %s\t\t",layers)
            for l in layers:
                logging.getLogger().debug("%s", l)
            o.write(layers)
            p = f.read_packet()
    
    
        f.close()
        o.close()
    
    if __name__ == "__main__":
        logging.getLogger().debug('Executing main')
        if (len(sys.argv) == 3):
            in_filename = str(sys.argv[1])
            out_filename = str(sys.argv[2])
            if os.path.exists(in_filename) == False:
                sys.stderr.write("Either {0} does not exist, or you do not have proper permissions\n".format(in_filename))
            else:
                foo(in_filename, out_filename)
        else:
            sys.stderr.write("USAGE: {0} <path to input file> <path to output file>\n".format(str(sys.argv[0])))            
    
c-is-best
  • 146
  • 2
  • 9

1 Answers1

2

I was finally able to answer my own two questions. See modified code below:

    # importing the os package (see api at http://docs.python.org/2.6/library/io.html)
    import os
    # import function 'basename' from module os.path
    from os.path import basename
    # importing the sys package (see api at http://docs.python.org/2.6/library/sys.html)
    import sys
    # importing the logging package (see api at http://docs.python.org/2.6/library/logging.html)
    import logging
    # by default Scapy attempts to find ipv6 routing information, 
    # and if it does not find any it prints out a warning when running the module.
    # the following statement changes log level to ERROR so that this warning will not 
    # occur 
    effective_level = logging.getLogger("scapy.runtime").getEffectiveLevel()
    logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
    # importing Scapy
    from scapy.all import PcapReader, PcapWriter
    from scapy.layers.l2 import GRE, GRErouting, NoPayload
    # return the log level o be what it was
    logging.getLogger("scapy.runtime").setLevel(effective_level)
    # unfortunately, somewhere in Scapy sys.stdout is being reset.
    # thus, using the 'print' command will not produce output to the console.
    # the following two lines place stdout back into sys.
    if sys.stdout != sys.__stdout__:
        sys.stdout = sys.__stdout__

    # this is a function declaration. there is no need for explicit types.
    # python can infer an object type from its usage
    def foo(in_filename, out_filename):
        # open the input file for reading
        f = PcapReader(in_filename)
        # open the output file for writing
        o = PcapWriter(out_filename)

        # read the first packet from the input file
        p = f.read_packet()

        # while we haven't processed the last packet
        while p:
            # gets the first layer of the current packet
            layer = p.firstlayer()
            # loop over the layers
            while not isinstance(layer, NoPayload):

                if layer.default_fields.has_key('chksum'):
                    del layer.chksum
                if layer.default_fields.has_key('len'):
                    del layer.len

                if (type(layer) is GRE):
                    layer.routing_present = 1
                    layer.chksum_present = 1
                    # make sure to delete the checksum field. hopefully scapy will calculate it correctly one day
                    del layer.chksum

                    gr = GRErouting()
                    gr.address_family = 0x0800
                    gr.SRE_len = 4
                    gr.SRE_offset = 0
                    gr.routing_info = "1111"
                    # the NULL routing field
                    empty_gr = GRErouting()
                    empty_gr.address_family = 0x0000
                    empty_gr.SRE_len = 0

                    gr.add_payload(empty_gr)
                    gr.add_payload(layer.payload)
                    layer.remove_payload()
                    layer.add_payload(gr)
                    layer = empty_gr

                # advance to the next layer
                layer = layer.payload


            # write the packet we just dissected into the output file    
            o.write(p)
            # read the next packet
            p = f.read_packet()

        # close the input file
        f.close()
        # close the output file
        o.close()

    # i believe this is needed only if we are running the this module
    # as the main module. i don't know if this will get executed if this module
    # is imported into some other main module
    if __name__ == "__main__":
        # letting the user know we are starting. 
        # sys.argv[0] includes the path to the module, including the module name.
        # convert sys.argv[0] into string, and extract the module name only
        # (using basename)
        print '===> Running', basename(str(sys.argv[0]))
        # making sure that two parameters were entered on the command line
        if (len(sys.argv) == 3):
            # get the path to the input file
            in_filename = str(sys.argv[1])
            # get the path to the output file
            out_filename = str(sys.argv[2])
            # make sure the input file actually exists.
            # if it doesn't, we print out an error and exit
            if os.path.exists(in_filename) == False:
                # note the method for entering conversion specifiers ({<ordinal>})
                sys.stderr.write("Either {0} does not exist, or you do not have proper permissions\n".format(in_filename))
            else:
                # if the input file does exist, execute 'foo'
                foo(in_filename, out_filename)
                # print an end script notification
                print basename(str(sys.argv[0])), '===> completed successfully'
        else:
            # write a USAGE message to the standard output stream
            sys.stderr.write("USAGE: {0} <path to input file> <path to output file>\n".format(basename(str(sys.argv[0]))))
c-is-best
  • 146
  • 2
  • 9