root/branch/PacketManipulator/PM/Backend/Scapy/packet.py @ 4882

Revision 4882, 7.7 kB (checked in by nopper, 4 years ago)

2009-06-13 Francesco Piccinno <stack.box@…>

  • attacks/run-tester.sh:
    • Simple attacktester.py runner to avoid setting PYTHONPATH at every run.
  • attacks/nose-tests.sh:
    • Simple launcher of nosetests to test the attacks by testing the doctest strings in main.py files.
  • attacks/attacktester.py:
    • Add interaction with PluginEngine?().tree to let the plugin tested with the attacktester.py to have Core().get_need() fully working without having the mess to define a setup.py. Really usefull while developing and testing.
    • Add the possibility to change the configuration by passing set expressions separated with ',' on the command line prefixed with -s.
    • Add a --quiet options to avoid printing useless messages.
    • Add a --profile option that uses hotshot module to profile the code.
  • PM/Core/AttackUtils.py:
    • Add a module to holds utilities functions used in various attacks.
    • Add attack_unittest() function used by doctest of various attacks.
  • attacks/offline/ethernet/sources/main.py attacks/offline/ip/sources/main.py:
    • Switching from coroutine to classic approach.
  • attacks/offline/tcp/sources/main.py:
    • Switching from coroutine to classic approach.
    • Add checksum checking.
  • attacks/offline/fingerprint/sources/main.py:
    • Add passive fingerprint attack that uses the same approach and db of ettercap.
  • attacks/pcap-tests/wrong-checksum.pcap:
    • Create a pcap-test/ file to holds pcap files used for testing purposes.
    • Add a wrong-checksum.pcap file used by tcp, ip and fingerprint attacks.
  • PM/Manager/AttackManager.py:
    • Dropped coroutine approach for evident limitation on threaded context and poor performance. Now we use tradition callable.
    • Add Configuration object to centralize and made easier task to manage configurations from a plugin and his relative methods to the manager.
    • Add user_msg() function for communicating message to the user with the same approach of syslog (severity and facility).
    • Add add_decoder_hook() method to the manager to provide a pre/post hook set mechanism for decoders functions. This is used for example in the fingerprint offline attack.
    • Now AttackPlugin? class has 2 additional methods register_options() and register_hooks().
  • PM/Core/Atoms.py:
    • Add ordered dict (odict) implementation to the Atoms module.
  • PM/Backend/Abstract/BaseContext/Timed.py:
    • print replaced with log.debug()
  • PM/Backend/Scapy/packet.py:
    • Add a cfields attribute to metapacket for managing custom fields created by attacks.
    • Add get_field(), set_cfield(), unset_cfield() functions.
  • General bug fixing.
  • Implemented custom fields by using a private dictionary.
  • Added nosetest architecture to test attacks by using doctest strings to speed up the development phase.
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (C) 2008 Adriano Monteiro Marques
4#
5# Author: Francesco Piccinno <stack.box@gmail.com>
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21from PM.Core.Logger import log
22from PM.Backend.Scapy.translator import global_trans
23from PM.Backend.Scapy.wrapper import Packet, NoPayload, Ether, RadioTap, \
24                                       Raw, IP, get_proto_size
25from PM.Core.NetConst import IL_TYPE_ETH, IL_TYPE_TR, IL_TYPE_FDDI, \
26                             IL_TYPE_RAWIP, IL_TYPE_WIFI, IL_TYPE_COOK, \
27                             IL_TYPE_PRISM
28
29class MetaPacket(object):
30    def __init__(self, proto=None, cfields=None):
31        self.root = proto
32        self.cfields = cfields or {}
33
34    def insert(self, proto, layer):
35        if layer == -1:
36            # Append
37            packet = self.root / proto.root
38            self.root = packet
39
40            return True
41        else:
42            # We have to insert proto at position layer
43
44            first = None
45            last = self.root
46
47            while layer > 0 and last:
48                first = last
49                last = last.payload
50                layer -= 1
51
52            ret = proto.root / last
53
54            if first:
55                first.payload = ret
56            else:
57                self.root = ret
58
59            return True
60    def complete(self):
61        # Add missing layers (Ethernet and IP)
62
63        if not self.root.haslayer(Ether):
64            if not self.root.haslayer(IP):
65                self.root = IP() / self.root
66
67            self.root = Ether() / self.root
68
69            return True
70
71        return False
72
73    def remove(self, rproto):
74        first = None
75        last = self.root
76
77        if isinstance(self.root.payload, NoPayload):
78            return False
79
80        while isinstance(last, Packet):
81
82            if last == rproto:
83                if first:
84                    first.payload = last.payload
85                else:
86                    self.root = last.payload
87
88                return True
89
90            first = last
91            last = last.payload
92
93        return False
94
95    def get_size(self):
96        return len(str(self.root))
97
98    def summary(self):
99        return self.root.summary()
100
101    def get_time(self):
102        #self.root.time
103        return self.root.sprintf("%.time%")
104
105    def get_source(self):
106        ip = self.root.sprintf("{IP:%IP.src%}")
107        hw = self.root.sprintf("{Ether:%Ether.src%}")
108
109        if ip:
110            return ip
111
112        if hw:
113            return hw
114
115        return "N/A"
116
117    def get_dest(self):
118        ip = self.root.sprintf("{IP:%IP.dst%}")
119        hw = self.root.sprintf("{Ether:%Ether.dst%}")
120
121        if ip:
122            return ip
123
124        if hw:
125            return hw
126
127        return "N/A"
128
129    def get_protocol_str(self):
130        proto = self.root
131
132        while isinstance(proto, Packet):
133            if isinstance(proto.payload, NoPayload) or \
134               isinstance(proto.payload, Raw):
135                return proto.name
136
137            proto = proto.payload
138
139    def get_protocols(self):
140        "@returns a list containing the name of protocols"
141
142        lst = []
143        proto = self.root
144
145        while isinstance(proto, Packet):
146            if isinstance(proto, NoPayload):
147                break
148
149            lst.append(proto)
150
151            proto = proto.payload
152
153        return lst
154
155    def get_protocol_bounds(self, proto_inst):
156        "@return a tuple (start, len)"
157
158        start = 0
159        proto = self.root
160
161        while isinstance(proto, Packet):
162            if isinstance(proto, NoPayload):
163                return None
164            elif proto_inst is proto:
165                return start, start + get_proto_size(proto_inst) / 8
166
167            start += get_proto_size(proto) / 8
168            proto = proto.payload
169
170    def reset(self, protocol=None, startproto=None, field=None):
171        """
172        Reset the packet
173
174        @param protocol the protocol to reset or None to match all
175        @param startproto the start protocolo to start from
176        @param field the field to reset or None to match all
177        @return True if reset is ok or False
178        """
179
180        protocol_found = False
181        current = (startproto is not None) and (startproto) or (self.root)
182
183        while isinstance(current, Packet) and \
184              not isinstance(current, NoPayload):
185
186            if protocol is not None and \
187               protocol is current:
188                protocol_found = True
189
190            elif protocol is not None and not protocol_found:
191                # We could skip the entire body of function because
192                # proto filtering is active and the current is not
193                # the target protocol.
194
195                current = find.payload
196                continue
197
198            if field is not None:
199                # We should look for field in the current protocol
200
201                if field in current.fields_desc:
202                    delattr(current, field.name)
203
204                    # Ok. Let's return because we have reached our
205                    # field!
206
207                    return
208            else:
209                # If we are here we should reset all the fields!
210                # kill them all man!
211
212                for k in current.fields.keys():
213                    delattr(current, k)
214
215            # If we have reached our proto we are sure that
216            # we have resetted the selected fields correctly
217            # at this point so it's safe to return
218
219            if protocol_found:
220                return
221
222            current = current.payload
223
224    def haslayer(self, layer):
225        return bool(self.root.haslayer(layer))
226
227    def getlayer(self, layer):
228        return self.root.getlayer(layer)
229
230    def get_raw(self):
231        return str(self.root)
232
233    def get_raw_layer(self, layer):
234        return str(self.getlayer(layer))
235
236    def rebuild_from_raw_payload(self, newpayload):
237        log.debug('Rebuilding packet starting from %s' % \
238                  str(self.root.__class__))
239
240        try:
241            new_proto = self.root.__class__(newpayload)
242            self.root = new_proto
243            return True
244        except Exception, err:
245            log.debug('Rebuild from raw failed (%s)' % str(err))
246            return False
247
248    # standard functions
249    def get_datalink(self):
250        if isinstance(self.root, Ether):
251            return IL_TYPE_ETH
252        if isinstance(self.root, RadioTap):
253            return IL_TYPE_WIFI
254        return None
255
256    def get_field(self, fieldname):
257        try:
258            ret = fieldname.split('.')
259            layer = self.root.getlayer(global_trans[ret[0]][0])
260
261            if len(ret) > 1:
262                return getattr(layer, ret[1])
263            else:
264                return str(layer)
265        except Exception, err:
266            raise err
267
268    def copy(self):
269        if self.root:
270            return MetaPacket(self.root.copy(),
271                               self.cfields.copy())
272
273
274    # Custom fields
275
276    def get_cfield(self, name):
277        return self.cfields[name]
278
279    def set_cfield(self, name, val):
280        self.cfields[name] = val
281
282    def unset_cfield(self, name):
283        del self.cfields[name]
Note: See TracBrowser for help on using the browser.