Scapy:插入一个新层并记录问题


  1. 我正在尝试使用Scapy在GRE和IP之间插入GRE路由层。我正在读取的pcap包含如下堆叠的单个数据包:以太网/IPv4/GRE/IPv4/IICMP。我看到的是getLayer返回当前层+其有效载荷,其中可能包括其他层,这对我来说不好。我只想获得当前层。当我为每一层获取层,然后编写整个数组时,我会得到一个奇怪的pcap,因为每一层都有额外的有效负载
  2. 我也无法使用简单的"打印"将任何数据输出到控制台。我知道这是因为Scapy添加了日志记录模块,并抑制了系统日志记录,但我想知道如何撤消它,并能够使用"print"语句。

    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: %stt",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 permissionsn".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])))            
    

我终于能够回答自己的两个问题了。参见下面的修改代码:

    # 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 permissionsn".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]))))

最新更新