1f7d24e3fSHanoh Haim## This file is part of Scapy
2f7d24e3fSHanoh Haim## See http://www.secdev.org/projects/scapy for more informations
3f7d24e3fSHanoh Haim## Copyright (C) Philippe Biondi <phil@secdev.org>
4f7d24e3fSHanoh Haim## This program is published under a GPLv2 license
5f7d24e3fSHanoh Haim
6f7d24e3fSHanoh Haim"""
7f7d24e3fSHanoh HaimIPv4 (Internet Protocol v4).
8f7d24e3fSHanoh Haim"""
9f7d24e3fSHanoh Haim
10f7d24e3fSHanoh Haimimport os,time,struct,re,socket,new
11f7d24e3fSHanoh Haimfrom select import select
12f7d24e3fSHanoh Haimfrom collections import defaultdict
13f7d24e3fSHanoh Haimfrom scapy.utils import checksum
14f7d24e3fSHanoh Haimfrom scapy.layers.l2 import *
15f7d24e3fSHanoh Haimfrom scapy.config import conf
16f7d24e3fSHanoh Haimfrom scapy.fields import *
17f7d24e3fSHanoh Haimfrom scapy.packet import *
18f7d24e3fSHanoh Haimfrom scapy.volatile import *
19f7d24e3fSHanoh Haimfrom scapy.sendrecv import sr,sr1,srp1
20f7d24e3fSHanoh Haimfrom scapy.plist import PacketList,SndRcvList
21f7d24e3fSHanoh Haimfrom scapy.automaton import Automaton,ATMT
22f7d24e3fSHanoh Haim
23f7d24e3fSHanoh Haimimport scapy.as_resolvers
24f7d24e3fSHanoh Haim
25f7d24e3fSHanoh Haim
26f7d24e3fSHanoh Haim####################
27f7d24e3fSHanoh Haim## IP Tools class ##
28f7d24e3fSHanoh Haim####################
29f7d24e3fSHanoh Haim
30f7d24e3fSHanoh Haimclass IPTools:
31f7d24e3fSHanoh Haim    """Add more powers to a class that have a "src" attribute."""
32f7d24e3fSHanoh Haim    def whois(self):
33f7d24e3fSHanoh Haim        os.system("whois %s" % self.src)
34f7d24e3fSHanoh Haim    def ottl(self):
35f7d24e3fSHanoh Haim        t = [32,64,128,255]+[self.ttl]
36f7d24e3fSHanoh Haim        t.sort()
37f7d24e3fSHanoh Haim        return t[t.index(self.ttl)+1]
38f7d24e3fSHanoh Haim    def hops(self):
39f7d24e3fSHanoh Haim        return self.ottl()-self.ttl-1
40f7d24e3fSHanoh Haim
41f7d24e3fSHanoh Haim
42f7d24e3fSHanoh Haim_ip_options_names = { 0: "end_of_list",
43f7d24e3fSHanoh Haim                      1: "nop",
44f7d24e3fSHanoh Haim                      2: "security",
45f7d24e3fSHanoh Haim                      3: "loose_source_route",
46f7d24e3fSHanoh Haim                      4: "timestamp",
47f7d24e3fSHanoh Haim                      5: "extended_security",
48f7d24e3fSHanoh Haim                      6: "commercial_security",
49f7d24e3fSHanoh Haim                      7: "record_route",
50f7d24e3fSHanoh Haim                      8: "stream_id",
51f7d24e3fSHanoh Haim                      9: "strict_source_route",
52f7d24e3fSHanoh Haim                      10: "experimental_measurement",
53f7d24e3fSHanoh Haim                      11: "mtu_probe",
54f7d24e3fSHanoh Haim                      12: "mtu_reply",
55f7d24e3fSHanoh Haim                      13: "flow_control",
56f7d24e3fSHanoh Haim                      14: "access_control",
57f7d24e3fSHanoh Haim                      15: "encode",
58f7d24e3fSHanoh Haim                      16: "imi_traffic_descriptor",
59f7d24e3fSHanoh Haim                      17: "extended_IP",
60f7d24e3fSHanoh Haim                      18: "traceroute",
61f7d24e3fSHanoh Haim                      19: "address_extension",
62f7d24e3fSHanoh Haim                      20: "router_alert",
63f7d24e3fSHanoh Haim                      21: "selective_directed_broadcast_mode",
64f7d24e3fSHanoh Haim                      23: "dynamic_packet_state",
65f7d24e3fSHanoh Haim                      24: "upstream_multicast_packet",
66f7d24e3fSHanoh Haim                      25: "quick_start",
67f7d24e3fSHanoh Haim                      30: "rfc4727_experiment",
68f7d24e3fSHanoh Haim                      }
69f7d24e3fSHanoh Haim
70f7d24e3fSHanoh Haim
71f7d24e3fSHanoh Haimclass _IPOption_HDR(Packet):
72f7d24e3fSHanoh Haim    fields_desc = [ BitField("copy_flag",0, 1),
73f7d24e3fSHanoh Haim                    BitEnumField("optclass",0,2,{0:"control",2:"debug"}),
74f7d24e3fSHanoh Haim                    BitEnumField("option",0,5, _ip_options_names) ]
75f7d24e3fSHanoh Haim
76f7d24e3fSHanoh Haimclass IPOption(Packet):
77f7d24e3fSHanoh Haim    name = "IP Option"
78f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
79f7d24e3fSHanoh Haim                    FieldLenField("length", None, fmt="B",  # Only option 0 and 1 have no length and value
80f7d24e3fSHanoh Haim                                  length_of="value", adjust=lambda pkt,l:l+2),
81f7d24e3fSHanoh Haim                    StrLenField("value", "",length_from=lambda pkt:pkt.length-2) ]
82f7d24e3fSHanoh Haim
83f7d24e3fSHanoh Haim    def extract_padding(self, p):
84f7d24e3fSHanoh Haim        return "",p
85f7d24e3fSHanoh Haim
86f7d24e3fSHanoh Haim    registered_ip_options = {}
87f7d24e3fSHanoh Haim    @classmethod
88f7d24e3fSHanoh Haim    def register_variant(cls):
89f7d24e3fSHanoh Haim        cls.registered_ip_options[cls.option.default] = cls
90f7d24e3fSHanoh Haim    @classmethod
91f7d24e3fSHanoh Haim    def dispatch_hook(cls, pkt=None, *args, **kargs):
92f7d24e3fSHanoh Haim        if pkt:
93f7d24e3fSHanoh Haim            opt = ord(pkt[0])&0x1f
94f7d24e3fSHanoh Haim            if opt in cls.registered_ip_options:
95f7d24e3fSHanoh Haim                return cls.registered_ip_options[opt]
96f7d24e3fSHanoh Haim        return cls
97f7d24e3fSHanoh Haim
98f7d24e3fSHanoh Haimclass IPOption_EOL(IPOption):
99f7d24e3fSHanoh Haim    name = "IP Option End of Options List"
100f7d24e3fSHanoh Haim    option = 0
101f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR ]
102f7d24e3fSHanoh Haim
103f7d24e3fSHanoh Haim
104f7d24e3fSHanoh Haimclass IPOption_NOP(IPOption):
105f7d24e3fSHanoh Haim    name = "IP Option No Operation"
106f7d24e3fSHanoh Haim    option=1
107f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR ]
108f7d24e3fSHanoh Haim
109f7d24e3fSHanoh Haimclass IPOption_Security(IPOption):
110f7d24e3fSHanoh Haim    name = "IP Option Security"
111f7d24e3fSHanoh Haim    copy_flag = 1
112f7d24e3fSHanoh Haim    option = 2
113f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
114f7d24e3fSHanoh Haim                    ByteField("length", 11),
115f7d24e3fSHanoh Haim                    ShortField("security",0),
116f7d24e3fSHanoh Haim                    ShortField("compartment",0),
117f7d24e3fSHanoh Haim                    ShortField("handling_restrictions",0),
118f7d24e3fSHanoh Haim                    StrFixedLenField("transmission_control_code","xxx",3),
119f7d24e3fSHanoh Haim                    ]
120f7d24e3fSHanoh Haim
121f7d24e3fSHanoh Haimclass IPOption_LSRR(IPOption):
122f7d24e3fSHanoh Haim    name = "IP Option Loose Source and Record Route"
123f7d24e3fSHanoh Haim    copy_flag = 1
124f7d24e3fSHanoh Haim    option = 3
125f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
126f7d24e3fSHanoh Haim                    FieldLenField("length", None, fmt="B",
127f7d24e3fSHanoh Haim                                  length_of="routers", adjust=lambda pkt,l:l+3),
128f7d24e3fSHanoh Haim                    ByteField("pointer",4), # 4 is first IP
129f7d24e3fSHanoh Haim                    FieldListField("routers",[],IPField("","0.0.0.0"),
130f7d24e3fSHanoh Haim                                   length_from=lambda pkt:pkt.length-3)
131f7d24e3fSHanoh Haim                    ]
132f7d24e3fSHanoh Haim    def get_current_router(self):
133f7d24e3fSHanoh Haim        return self.routers[self.pointer/4-1]
134f7d24e3fSHanoh Haim
135f7d24e3fSHanoh Haimclass IPOption_RR(IPOption_LSRR):
136f7d24e3fSHanoh Haim    name = "IP Option Record Route"
137f7d24e3fSHanoh Haim    option = 7
138f7d24e3fSHanoh Haim
139f7d24e3fSHanoh Haimclass IPOption_SSRR(IPOption_LSRR):
140f7d24e3fSHanoh Haim    name = "IP Option Strict Source and Record Route"
141f7d24e3fSHanoh Haim    option = 9
142f7d24e3fSHanoh Haim
143f7d24e3fSHanoh Haimclass IPOption_Stream_Id(IPOption):
144f7d24e3fSHanoh Haim    name = "IP Option Stream ID"
145f7d24e3fSHanoh Haim    option = 8
146f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
147f7d24e3fSHanoh Haim                    ByteField("length", 4),
148f7d24e3fSHanoh Haim                    ShortField("security",0), ]
149f7d24e3fSHanoh Haim
150f7d24e3fSHanoh Haimclass IPOption_MTU_Probe(IPOption):
151f7d24e3fSHanoh Haim    name = "IP Option MTU Probe"
152f7d24e3fSHanoh Haim    option = 11
153f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
154f7d24e3fSHanoh Haim                    ByteField("length", 4),
155f7d24e3fSHanoh Haim                    ShortField("mtu",0), ]
156f7d24e3fSHanoh Haim
157f7d24e3fSHanoh Haimclass IPOption_MTU_Reply(IPOption_MTU_Probe):
158f7d24e3fSHanoh Haim    name = "IP Option MTU Reply"
159f7d24e3fSHanoh Haim    option = 12
160f7d24e3fSHanoh Haim
161f7d24e3fSHanoh Haimclass IPOption_Traceroute(IPOption):
162f7d24e3fSHanoh Haim    name = "IP Option Traceroute"
163f7d24e3fSHanoh Haim    copy_flag = 1
164f7d24e3fSHanoh Haim    option = 18
165f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
166f7d24e3fSHanoh Haim                    ByteField("length", 12),
167f7d24e3fSHanoh Haim                    ShortField("id",0),
168f7d24e3fSHanoh Haim                    ShortField("outbound_hops",0),
169f7d24e3fSHanoh Haim                    ShortField("return_hops",0),
170f7d24e3fSHanoh Haim                    IPField("originator_ip","0.0.0.0") ]
171f7d24e3fSHanoh Haim
172f7d24e3fSHanoh Haimclass IPOption_Address_Extension(IPOption):
173f7d24e3fSHanoh Haim    name = "IP Option Address Extension"
174f7d24e3fSHanoh Haim    copy_flag = 1
175f7d24e3fSHanoh Haim    option = 19
176f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
177f7d24e3fSHanoh Haim                    ByteField("length", 10),
178f7d24e3fSHanoh Haim                    IPField("src_ext","0.0.0.0"),
179f7d24e3fSHanoh Haim                    IPField("dst_ext","0.0.0.0") ]
180f7d24e3fSHanoh Haim
181f7d24e3fSHanoh Haimclass IPOption_Router_Alert(IPOption):
182f7d24e3fSHanoh Haim    name = "IP Option Router Alert"
183f7d24e3fSHanoh Haim    copy_flag = 1
184f7d24e3fSHanoh Haim    option = 20
185f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
186f7d24e3fSHanoh Haim                    ByteField("length", 4),
187f7d24e3fSHanoh Haim                    ShortEnumField("alert",0, {0:"router_shall_examine_packet"}), ]
188f7d24e3fSHanoh Haim
189f7d24e3fSHanoh Haim
190f7d24e3fSHanoh Haimclass IPOption_SDBM(IPOption):
191f7d24e3fSHanoh Haim    name = "IP Option Selective Directed Broadcast Mode"
192f7d24e3fSHanoh Haim    copy_flag = 1
193f7d24e3fSHanoh Haim    option = 21
194f7d24e3fSHanoh Haim    fields_desc = [ _IPOption_HDR,
195f7d24e3fSHanoh Haim                    FieldLenField("length", None, fmt="B",
196f7d24e3fSHanoh Haim                                  length_of="addresses", adjust=lambda pkt,l:l+2),
197f7d24e3fSHanoh Haim                    FieldListField("addresses",[],IPField("","0.0.0.0"),
198f7d24e3fSHanoh Haim                                   length_from=lambda pkt:pkt.length-2)
199f7d24e3fSHanoh Haim                    ]
200f7d24e3fSHanoh Haim
201f7d24e3fSHanoh Haim
202f7d24e3fSHanoh Haim
203f7d24e3fSHanoh HaimTCPOptions = (
204f7d24e3fSHanoh Haim              { 0 : ("EOL",None),
205f7d24e3fSHanoh Haim                1 : ("NOP",None),
206f7d24e3fSHanoh Haim                2 : ("MSS","!H"),
207f7d24e3fSHanoh Haim                3 : ("WScale","!B"),
208f7d24e3fSHanoh Haim                4 : ("SAckOK",None),
209f7d24e3fSHanoh Haim                5 : ("SAck","!"),
210f7d24e3fSHanoh Haim                8 : ("Timestamp","!II"),
211f7d24e3fSHanoh Haim                14 : ("AltChkSum","!BH"),
212f7d24e3fSHanoh Haim                15 : ("AltChkSumOpt",None),
213f7d24e3fSHanoh Haim                25 : ("Mood","!p")
214f7d24e3fSHanoh Haim                },
215f7d24e3fSHanoh Haim              { "EOL":0,
216f7d24e3fSHanoh Haim                "NOP":1,
217f7d24e3fSHanoh Haim                "MSS":2,
218f7d24e3fSHanoh Haim                "WScale":3,
219f7d24e3fSHanoh Haim                "SAckOK":4,
220f7d24e3fSHanoh Haim                "SAck":5,
221f7d24e3fSHanoh Haim                "Timestamp":8,
222f7d24e3fSHanoh Haim                "AltChkSum":14,
223f7d24e3fSHanoh Haim                "AltChkSumOpt":15,
224f7d24e3fSHanoh Haim                "Mood":25
225f7d24e3fSHanoh Haim                } )
226f7d24e3fSHanoh Haim
227f7d24e3fSHanoh Haimclass TCPOptionsField(StrField):
228f7d24e3fSHanoh Haim    islist=1
229f7d24e3fSHanoh Haim    def getfield(self, pkt, s):
230f7d24e3fSHanoh Haim        opsz = (pkt.dataofs-5)*4
231f7d24e3fSHanoh Haim        if opsz < 0:
232f7d24e3fSHanoh Haim            warning("bad dataofs (%i). Assuming dataofs=5"%pkt.dataofs)
233f7d24e3fSHanoh Haim            opsz = 0
234f7d24e3fSHanoh Haim        return s[opsz:],self.m2i(pkt,s[:opsz])
235f7d24e3fSHanoh Haim    def m2i(self, pkt, x):
236f7d24e3fSHanoh Haim        opt = []
237f7d24e3fSHanoh Haim        while x:
238f7d24e3fSHanoh Haim            onum = ord(x[0])
239f7d24e3fSHanoh Haim            if onum == 0:
240f7d24e3fSHanoh Haim                opt.append(("EOL",None))
241f7d24e3fSHanoh Haim                x=x[1:]
242f7d24e3fSHanoh Haim                break
243f7d24e3fSHanoh Haim            if onum == 1:
244f7d24e3fSHanoh Haim                opt.append(("NOP",None))
245f7d24e3fSHanoh Haim                x=x[1:]
246f7d24e3fSHanoh Haim                continue
247f7d24e3fSHanoh Haim            olen = ord(x[1])
248f7d24e3fSHanoh Haim            if olen < 2:
249f7d24e3fSHanoh Haim                warning("Malformed TCP option (announced length is %i)" % olen)
250f7d24e3fSHanoh Haim                olen = 2
251f7d24e3fSHanoh Haim            oval = x[2:olen]
252f7d24e3fSHanoh Haim            if TCPOptions[0].has_key(onum):
253f7d24e3fSHanoh Haim                oname, ofmt = TCPOptions[0][onum]
254f7d24e3fSHanoh Haim                if onum == 5: #SAck
255f7d24e3fSHanoh Haim                    ofmt += "%iI" % (len(oval)/4)
256f7d24e3fSHanoh Haim                if ofmt and struct.calcsize(ofmt) == len(oval):
257f7d24e3fSHanoh Haim                    oval = struct.unpack(ofmt, oval)
258f7d24e3fSHanoh Haim                    if len(oval) == 1:
259f7d24e3fSHanoh Haim                        oval = oval[0]
260f7d24e3fSHanoh Haim                opt.append((oname, oval))
261f7d24e3fSHanoh Haim            else:
262f7d24e3fSHanoh Haim                opt.append((onum, oval))
263f7d24e3fSHanoh Haim            x = x[olen:]
264f7d24e3fSHanoh Haim        return opt
265f7d24e3fSHanoh Haim
266f7d24e3fSHanoh Haim    def i2m(self, pkt, x):
267f7d24e3fSHanoh Haim        opt = ""
268f7d24e3fSHanoh Haim        for oname,oval in x:
269f7d24e3fSHanoh Haim            if type(oname) is str:
270f7d24e3fSHanoh Haim                if oname == "NOP":
271f7d24e3fSHanoh Haim                    opt += "\x01"
272f7d24e3fSHanoh Haim                    continue
273f7d24e3fSHanoh Haim                elif oname == "EOL":
274f7d24e3fSHanoh Haim                    opt += "\x00"
275f7d24e3fSHanoh Haim                    continue
276f7d24e3fSHanoh Haim                elif TCPOptions[1].has_key(oname):
277f7d24e3fSHanoh Haim                    onum = TCPOptions[1][oname]
278f7d24e3fSHanoh Haim                    ofmt = TCPOptions[0][onum][1]
279f7d24e3fSHanoh Haim                    if onum == 5: #SAck
280f7d24e3fSHanoh Haim                        ofmt += "%iI" % len(oval)
281f7d24e3fSHanoh Haim                    if ofmt is not None and (type(oval) is not str or "s" in ofmt):
282f7d24e3fSHanoh Haim                        if type(oval) is not tuple:
283f7d24e3fSHanoh Haim                            oval = (oval,)
284f7d24e3fSHanoh Haim                        oval = struct.pack(ofmt, *oval)
285f7d24e3fSHanoh Haim                else:
286f7d24e3fSHanoh Haim                    warning("option [%s] unknown. Skipped."%oname)
287f7d24e3fSHanoh Haim                    continue
288f7d24e3fSHanoh Haim            else:
289f7d24e3fSHanoh Haim                onum = oname
290f7d24e3fSHanoh Haim                if type(oval) is not str:
291f7d24e3fSHanoh Haim                    warning("option [%i] is not string."%onum)
292f7d24e3fSHanoh Haim                    continue
293f7d24e3fSHanoh Haim            opt += chr(onum)+chr(2+len(oval))+oval
294f7d24e3fSHanoh Haim        return opt+"\x00"*(3-((len(opt)+3)%4))
295f7d24e3fSHanoh Haim    def randval(self):
296f7d24e3fSHanoh Haim        return [] # XXX
297f7d24e3fSHanoh Haim
298f7d24e3fSHanoh Haim
299f7d24e3fSHanoh Haimclass ICMPTimeStampField(IntField):
300f7d24e3fSHanoh Haim    re_hmsm = re.compile("([0-2]?[0-9])[Hh:](([0-5]?[0-9])([Mm:]([0-5]?[0-9])([sS:.]([0-9]{0,3}))?)?)?$")
301f7d24e3fSHanoh Haim    def i2repr(self, pkt, val):
302f7d24e3fSHanoh Haim        if val is None:
303f7d24e3fSHanoh Haim            return "--"
304f7d24e3fSHanoh Haim        else:
305f7d24e3fSHanoh Haim            sec, milli = divmod(val, 1000)
306f7d24e3fSHanoh Haim            min, sec = divmod(sec, 60)
307f7d24e3fSHanoh Haim            hour, min = divmod(min, 60)
308f7d24e3fSHanoh Haim            return "%d:%d:%d.%d" %(hour, min, sec, int(milli))
309f7d24e3fSHanoh Haim    def any2i(self, pkt, val):
310f7d24e3fSHanoh Haim        if type(val) is str:
311f7d24e3fSHanoh Haim            hmsms = self.re_hmsm.match(val)
312f7d24e3fSHanoh Haim            if hmsms:
313f7d24e3fSHanoh Haim                h,_,m,_,s,_,ms = hmsms = hmsms.groups()
314f7d24e3fSHanoh Haim                ms = int(((ms or "")+"000")[:3])
315f7d24e3fSHanoh Haim                val = ((int(h)*60+int(m or 0))*60+int(s or 0))*1000+ms
316f7d24e3fSHanoh Haim            else:
317f7d24e3fSHanoh Haim                val = 0
318f7d24e3fSHanoh Haim        elif val is None:
319f7d24e3fSHanoh Haim            val = int((time.time()%(24*60*60))*1000)
320f7d24e3fSHanoh Haim        return val
321f7d24e3fSHanoh Haim
322f7d24e3fSHanoh Haim
323f7d24e3fSHanoh Haimclass IP(Packet, IPTools):
324f7d24e3fSHanoh Haim    name = "IP"
325f7d24e3fSHanoh Haim    fields_desc = [ BitField("version" , 4 , 4),
326f7d24e3fSHanoh Haim                    BitField("ihl", None, 4),
327f7d24e3fSHanoh Haim                    XByteField("tos", 0),
328f7d24e3fSHanoh Haim                    ShortField("len", None),
329f7d24e3fSHanoh Haim                    ShortField("id", 1),
330f7d24e3fSHanoh Haim                    FlagsField("flags", 0, 3, ["MF","DF","evil"]),
331f7d24e3fSHanoh Haim                    BitField("frag", 0, 13),
332f7d24e3fSHanoh Haim                    ByteField("ttl", 64),
333f7d24e3fSHanoh Haim                    ByteEnumField("proto", 0, IP_PROTOS),
334f7d24e3fSHanoh Haim                    XShortField("chksum", None),
335f7d24e3fSHanoh Haim                    #IPField("src", "127.0.0.1"),
336f7d24e3fSHanoh Haim                    #Emph(SourceIPField("src","dst")),
337f7d24e3fSHanoh Haim                    Emph(IPField("src", "16.0.0.1")),
338f7d24e3fSHanoh Haim                    Emph(IPField("dst", "48.0.0.1")),
339f7d24e3fSHanoh Haim                    PacketListField("options", [], IPOption, length_from=lambda p:p.ihl*4-20) ]
340f7d24e3fSHanoh Haim    def post_build(self, p, pay):
341f7d24e3fSHanoh Haim        ihl = self.ihl
342f7d24e3fSHanoh Haim        p += "\0"*((-len(p))%4) # pad IP options if needed
343f7d24e3fSHanoh Haim        if ihl is None:
344f7d24e3fSHanoh Haim            ihl = len(p)/4
345f7d24e3fSHanoh Haim            p = chr(((self.version&0xf)<<4) | ihl&0x0f)+p[1:]
346f7d24e3fSHanoh Haim        if self.len is None:
347f7d24e3fSHanoh Haim            l = len(p)+len(pay)
348f7d24e3fSHanoh Haim            p = p[:2]+struct.pack("!H", l)+p[4:]
349f7d24e3fSHanoh Haim        if self.chksum is None:
350f7d24e3fSHanoh Haim            ck = checksum(p)
351f7d24e3fSHanoh Haim            p = p[:10]+chr(ck>>8)+chr(ck&0xff)+p[12:]
352f7d24e3fSHanoh Haim        return p+pay
353f7d24e3fSHanoh Haim
354f7d24e3fSHanoh Haim    def extract_padding(self, s):
355f7d24e3fSHanoh Haim        l = self.len - (self.ihl << 2)
356f7d24e3fSHanoh Haim        return s[:l],s[l:]
357f7d24e3fSHanoh Haim
358f7d24e3fSHanoh Haim    def send(self, s, slp=0):
359f7d24e3fSHanoh Haim        for p in self:
360f7d24e3fSHanoh Haim            try:
361f7d24e3fSHanoh Haim                s.sendto(str(p), (p.dst,0))
362f7d24e3fSHanoh Haim            except socket.error, msg:
363f7d24e3fSHanoh Haim                log_runtime.error(msg)
364f7d24e3fSHanoh Haim            if slp:
365f7d24e3fSHanoh Haim                time.sleep(slp)
366f7d24e3fSHanoh Haim    def route(self):
367f7d24e3fSHanoh Haim        dst = self.dst
368f7d24e3fSHanoh Haim        if isinstance(dst,Gen):
369f7d24e3fSHanoh Haim            dst = iter(dst).next()
370f7d24e3fSHanoh Haim        return conf.route.route(dst)
371f7d24e3fSHanoh Haim    def hashret(self):
372f7d24e3fSHanoh Haim        if ( (self.proto == socket.IPPROTO_ICMP)
373f7d24e3fSHanoh Haim             and (isinstance(self.payload, ICMP))
374f7d24e3fSHanoh Haim             and (self.payload.type in [3,4,5,11,12]) ):
375f7d24e3fSHanoh Haim            return self.payload.payload.hashret()
376f7d24e3fSHanoh Haim        else:
377f7d24e3fSHanoh Haim            if conf.checkIPsrc and conf.checkIPaddr:
378f7d24e3fSHanoh Haim                return strxor(inet_aton(self.src),inet_aton(self.dst))+struct.pack("B",self.proto)+self.payload.hashret()
379f7d24e3fSHanoh Haim            else:
380f7d24e3fSHanoh Haim                return struct.pack("B", self.proto)+self.payload.hashret()
381f7d24e3fSHanoh Haim    def answers(self, other):
382f7d24e3fSHanoh Haim        if not isinstance(other,IP):
383f7d24e3fSHanoh Haim            return 0
384f7d24e3fSHanoh Haim        if conf.checkIPaddr and (self.dst != other.src):
385f7d24e3fSHanoh Haim            return 0
386f7d24e3fSHanoh Haim        if ( (self.proto == socket.IPPROTO_ICMP) and
387f7d24e3fSHanoh Haim             (isinstance(self.payload, ICMP)) and
388f7d24e3fSHanoh Haim             (self.payload.type in [3,4,5,11,12]) ):
389f7d24e3fSHanoh Haim            # ICMP error message
390f7d24e3fSHanoh Haim            return self.payload.payload.answers(other)
391f7d24e3fSHanoh Haim
392f7d24e3fSHanoh Haim        else:
393f7d24e3fSHanoh Haim            if ( (conf.checkIPaddr and (self.src != other.dst)) or
394f7d24e3fSHanoh Haim                 (self.proto != other.proto) ):
395f7d24e3fSHanoh Haim                return 0
396f7d24e3fSHanoh Haim            return self.payload.answers(other.payload)
397f7d24e3fSHanoh Haim    def mysummary(self):
398f7d24e3fSHanoh Haim        s = self.sprintf("%IP.src% > %IP.dst% %IP.proto%")
399f7d24e3fSHanoh Haim        if self.frag:
400f7d24e3fSHanoh Haim            s += " frag:%i" % self.frag
401f7d24e3fSHanoh Haim        return s
402f7d24e3fSHanoh Haim
403f7d24e3fSHanoh Haim    def fragment(self, fragsize=1480):
404f7d24e3fSHanoh Haim        """Fragment IP datagrams"""
405f7d24e3fSHanoh Haim        fragsize = (fragsize+7)/8*8
406f7d24e3fSHanoh Haim        lst = []
407f7d24e3fSHanoh Haim        fnb = 0
408f7d24e3fSHanoh Haim        fl = self
409f7d24e3fSHanoh Haim        while fl.underlayer is not None:
410f7d24e3fSHanoh Haim            fnb += 1
411f7d24e3fSHanoh Haim            fl = fl.underlayer
412f7d24e3fSHanoh Haim
413f7d24e3fSHanoh Haim        for p in fl:
414f7d24e3fSHanoh Haim            s = str(p[fnb].payload)
415f7d24e3fSHanoh Haim            nb = (len(s)+fragsize-1)/fragsize
416f7d24e3fSHanoh Haim            for i in range(nb):
417f7d24e3fSHanoh Haim                q = p.copy()
418f7d24e3fSHanoh Haim                del(q[fnb].payload)
419f7d24e3fSHanoh Haim                del(q[fnb].chksum)
420f7d24e3fSHanoh Haim                del(q[fnb].len)
421f7d24e3fSHanoh Haim                if i == nb-1:
422f7d24e3fSHanoh Haim                    q[IP].flags &= ~1
423f7d24e3fSHanoh Haim                else:
424f7d24e3fSHanoh Haim                    q[IP].flags |= 1
425f7d24e3fSHanoh Haim                q[IP].frag = i*fragsize/8
426f7d24e3fSHanoh Haim                r = conf.raw_layer(load=s[i*fragsize:(i+1)*fragsize])
427f7d24e3fSHanoh Haim                r.overload_fields = p[IP].payload.overload_fields.copy()
428f7d24e3fSHanoh Haim                q.add_payload(r)
429f7d24e3fSHanoh Haim                lst.append(q)
430f7d24e3fSHanoh Haim        return lst
431f7d24e3fSHanoh Haim
432f7d24e3fSHanoh Haim
433f7d24e3fSHanoh Haimclass TCP(Packet):
434f7d24e3fSHanoh Haim    name = "TCP"
435f7d24e3fSHanoh Haim    fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES),
436f7d24e3fSHanoh Haim                    ShortEnumField("dport", 80, TCP_SERVICES),
437f7d24e3fSHanoh Haim                    IntField("seq", 0),
438f7d24e3fSHanoh Haim                    IntField("ack", 0),
439f7d24e3fSHanoh Haim                    BitField("dataofs", None, 4),
440f7d24e3fSHanoh Haim                    BitField("reserved", 0, 4),
441f7d24e3fSHanoh Haim                    FlagsField("flags", 0x2, 8, "FSRPAUEC"),
442f7d24e3fSHanoh Haim                    ShortField("window", 8192),
443f7d24e3fSHanoh Haim                    XShortField("chksum", None),
444f7d24e3fSHanoh Haim                    ShortField("urgptr", 0),
445f7d24e3fSHanoh Haim                    TCPOptionsField("options", {}) ]
446f7d24e3fSHanoh Haim    def post_build(self, p, pay):
447f7d24e3fSHanoh Haim        p += pay
448f7d24e3fSHanoh Haim        dataofs = self.dataofs
449f7d24e3fSHanoh Haim        if dataofs is None:
450f7d24e3fSHanoh Haim            dataofs = 5+((len(self.get_field("options").i2m(self,self.options))+3)/4)
451f7d24e3fSHanoh Haim            p = p[:12]+chr((dataofs << 4) | ord(p[12])&0x0f)+p[13:]
452f7d24e3fSHanoh Haim        if self.chksum is None:
453f7d24e3fSHanoh Haim            if isinstance(self.underlayer, IP):
454f7d24e3fSHanoh Haim                if self.underlayer.len is not None:
455f7d24e3fSHanoh Haim                    ln = self.underlayer.len-20
456f7d24e3fSHanoh Haim                else:
457f7d24e3fSHanoh Haim                    ln = len(p)
458f7d24e3fSHanoh Haim                psdhdr = struct.pack("!4s4sHH",
459f7d24e3fSHanoh Haim                                     inet_aton(self.underlayer.src),
460f7d24e3fSHanoh Haim                                     inet_aton(self.underlayer.dst),
461f7d24e3fSHanoh Haim                                     self.underlayer.proto,
462f7d24e3fSHanoh Haim                                     ln)
463f7d24e3fSHanoh Haim                ck=checksum(psdhdr+p)
464f7d24e3fSHanoh Haim                p = p[:16]+struct.pack("!H", ck)+p[18:]
465f7d24e3fSHanoh Haim            elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr):
466f7d24e3fSHanoh Haim                ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_TCP, self.underlayer, p)
467f7d24e3fSHanoh Haim                p = p[:16]+struct.pack("!H", ck)+p[18:]
468f7d24e3fSHanoh Haim            else:
469f7d24e3fSHanoh Haim                warning("No IP underlayer to compute checksum. Leaving null.")
470f7d24e3fSHanoh Haim        return p
471f7d24e3fSHanoh Haim    def hashret(self):
472f7d24e3fSHanoh Haim        if conf.checkIPsrc:
473f7d24e3fSHanoh Haim            return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret()
474f7d24e3fSHanoh Haim        else:
475f7d24e3fSHanoh Haim            return self.payload.hashret()
476f7d24e3fSHanoh Haim    def answers(self, other):
477f7d24e3fSHanoh Haim        if not isinstance(other, TCP):
478f7d24e3fSHanoh Haim            return 0
479f7d24e3fSHanoh Haim        if conf.checkIPsrc:
480f7d24e3fSHanoh Haim            if not ((self.sport == other.dport) and
481f7d24e3fSHanoh Haim                    (self.dport == other.sport)):
482f7d24e3fSHanoh Haim                return 0
483f7d24e3fSHanoh Haim        if (abs(other.seq-self.ack) > 2+len(other.payload)):
484f7d24e3fSHanoh Haim            return 0
485f7d24e3fSHanoh Haim        return 1
486f7d24e3fSHanoh Haim    def mysummary(self):
487f7d24e3fSHanoh Haim        if isinstance(self.underlayer, IP):
488f7d24e3fSHanoh Haim            return self.underlayer.sprintf("TCP %IP.src%:%TCP.sport% > %IP.dst%:%TCP.dport% %TCP.flags%")
489f7d24e3fSHanoh Haim        elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6):
490f7d24e3fSHanoh Haim            return self.underlayer.sprintf("TCP %IPv6.src%:%TCP.sport% > %IPv6.dst%:%TCP.dport% %TCP.flags%")
491f7d24e3fSHanoh Haim        else:
492f7d24e3fSHanoh Haim            return self.sprintf("TCP %TCP.sport% > %TCP.dport% %TCP.flags%")
493f7d24e3fSHanoh Haim
494f7d24e3fSHanoh Haimclass UDP(Packet):
495f7d24e3fSHanoh Haim    name = "UDP"
496f7d24e3fSHanoh Haim    fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES),
497f7d24e3fSHanoh Haim                    ShortEnumField("dport", 53, UDP_SERVICES),
498f7d24e3fSHanoh Haim                    ShortField("len", None),
499f7d24e3fSHanoh Haim                    XShortField("chksum", None), ]
500f7d24e3fSHanoh Haim    def post_build(self, p, pay):
501f7d24e3fSHanoh Haim        p += pay
502f7d24e3fSHanoh Haim        l = self.len
503f7d24e3fSHanoh Haim        if l is None:
504f7d24e3fSHanoh Haim            l = len(p)
505f7d24e3fSHanoh Haim            p = p[:4]+struct.pack("!H",l)+p[6:]
506f7d24e3fSHanoh Haim        if self.chksum is None:
507f7d24e3fSHanoh Haim            if isinstance(self.underlayer, IP):
508f7d24e3fSHanoh Haim                if self.underlayer.len is not None:
509f7d24e3fSHanoh Haim                    ln = self.underlayer.len-20
510f7d24e3fSHanoh Haim                else:
511f7d24e3fSHanoh Haim                    ln = len(p)
512f7d24e3fSHanoh Haim                psdhdr = struct.pack("!4s4sHH",
513f7d24e3fSHanoh Haim                                     inet_aton(self.underlayer.src),
514f7d24e3fSHanoh Haim                                     inet_aton(self.underlayer.dst),
515f7d24e3fSHanoh Haim                                     self.underlayer.proto,
516f7d24e3fSHanoh Haim                                     ln)
517f7d24e3fSHanoh Haim                ck=checksum(psdhdr+p)
518f7d24e3fSHanoh Haim                p = p[:6]+struct.pack("!H", ck)+p[8:]
519f7d24e3fSHanoh Haim            elif isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr):
520f7d24e3fSHanoh Haim                ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_UDP, self.underlayer, p)
521f7d24e3fSHanoh Haim                p = p[:6]+struct.pack("!H", ck)+p[8:]
522f7d24e3fSHanoh Haim            else:
523f7d24e3fSHanoh Haim                warning("No IP underlayer to compute checksum. Leaving null.")
524f7d24e3fSHanoh Haim        return p
525f7d24e3fSHanoh Haim    def extract_padding(self, s):
526f7d24e3fSHanoh Haim        l = self.len - 8
527f7d24e3fSHanoh Haim        return s[:l],s[l:]
528f7d24e3fSHanoh Haim    def hashret(self):
529f7d24e3fSHanoh Haim        return self.payload.hashret()
530f7d24e3fSHanoh Haim    def answers(self, other):
531f7d24e3fSHanoh Haim        if not isinstance(other, UDP):
532f7d24e3fSHanoh Haim            return 0
533f7d24e3fSHanoh Haim        if conf.checkIPsrc:
534f7d24e3fSHanoh Haim            if self.dport != other.sport:
535f7d24e3fSHanoh Haim                return 0
536f7d24e3fSHanoh Haim        return self.payload.answers(other.payload)
537f7d24e3fSHanoh Haim    def mysummary(self):
538f7d24e3fSHanoh Haim        if isinstance(self.underlayer, IP):
539f7d24e3fSHanoh Haim            return self.underlayer.sprintf("UDP %IP.src%:%UDP.sport% > %IP.dst%:%UDP.dport%")
540f7d24e3fSHanoh Haim        elif isinstance(self.underlayer, scapy.layers.inet6.IPv6):
541f7d24e3fSHanoh Haim            return self.underlayer.sprintf("UDP %IPv6.src%:%UDP.sport% > %IPv6.dst%:%UDP.dport%")
542f7d24e3fSHanoh Haim        else:
543f7d24e3fSHanoh Haim            return self.sprintf("UDP %UDP.sport% > %UDP.dport%")
544f7d24e3fSHanoh Haim
545f7d24e3fSHanoh Haimicmptypes = { 0 : "echo-reply",
546f7d24e3fSHanoh Haim              3 : "dest-unreach",
547f7d24e3fSHanoh Haim              4 : "source-quench",
548f7d24e3fSHanoh Haim              5 : "redirect",
549f7d24e3fSHanoh Haim              8 : "echo-request",
550f7d24e3fSHanoh Haim              9 : "router-advertisement",
551f7d24e3fSHanoh Haim              10 : "router-solicitation",
552f7d24e3fSHanoh Haim              11 : "time-exceeded",
553f7d24e3fSHanoh Haim              12 : "parameter-problem",
554f7d24e3fSHanoh Haim              13 : "timestamp-request",
555f7d24e3fSHanoh Haim              14 : "timestamp-reply",
556f7d24e3fSHanoh Haim              15 : "information-request",
557f7d24e3fSHanoh Haim              16 : "information-response",
558f7d24e3fSHanoh Haim              17 : "address-mask-request",
559f7d24e3fSHanoh Haim              18 : "address-mask-reply" }
560f7d24e3fSHanoh Haim
561f7d24e3fSHanoh Haimicmpcodes = { 3 : { 0  : "network-unreachable",
562f7d24e3fSHanoh Haim                    1  : "host-unreachable",
563f7d24e3fSHanoh Haim                    2  : "protocol-unreachable",
564f7d24e3fSHanoh Haim                    3  : "port-unreachable",
565f7d24e3fSHanoh Haim                    4  : "fragmentation-needed",
566f7d24e3fSHanoh Haim                    5  : "source-route-failed",
567f7d24e3fSHanoh Haim                    6  : "network-unknown",
568f7d24e3fSHanoh Haim                    7  : "host-unknown",
569f7d24e3fSHanoh Haim                    9  : "network-prohibited",
570f7d24e3fSHanoh Haim                    10 : "host-prohibited",
571f7d24e3fSHanoh Haim                    11 : "TOS-network-unreachable",
572f7d24e3fSHanoh Haim                    12 : "TOS-host-unreachable",
573f7d24e3fSHanoh Haim                    13 : "communication-prohibited",
574f7d24e3fSHanoh Haim                    14 : "host-precedence-violation",
575f7d24e3fSHanoh Haim                    15 : "precedence-cutoff", },
576f7d24e3fSHanoh Haim              5 : { 0  : "network-redirect",
577f7d24e3fSHanoh Haim                    1  : "host-redirect",
578f7d24e3fSHanoh Haim                    2  : "TOS-network-redirect",
579f7d24e3fSHanoh Haim                    3  : "TOS-host-redirect", },
580f7d24e3fSHanoh Haim              11 : { 0 : "ttl-zero-during-transit",
581f7d24e3fSHanoh Haim                     1 : "ttl-zero-during-reassembly", },
582f7d24e3fSHanoh Haim              12 : { 0 : "ip-header-bad",
583f7d24e3fSHanoh Haim                     1 : "required-option-missing", }, }
584f7d24e3fSHanoh Haim
585f7d24e3fSHanoh Haim
586f7d24e3fSHanoh Haim
587f7d24e3fSHanoh Haim
588f7d24e3fSHanoh Haimclass ICMP(Packet):
589f7d24e3fSHanoh Haim    name = "ICMP"
590f7d24e3fSHanoh Haim    fields_desc = [ ByteEnumField("type",8, icmptypes),
591f7d24e3fSHanoh Haim                    MultiEnumField("code",0, icmpcodes, depends_on=lambda pkt:pkt.type,fmt="B"),
592f7d24e3fSHanoh Haim                    XShortField("chksum", None),
593f7d24e3fSHanoh Haim                    ConditionalField(XShortField("id",0),  lambda pkt:pkt.type in [0,8,13,14,15,16,17,18]),
594f7d24e3fSHanoh Haim                    ConditionalField(XShortField("seq",0), lambda pkt:pkt.type in [0,8,13,14,15,16,17,18]),
595f7d24e3fSHanoh Haim                    ConditionalField(ICMPTimeStampField("ts_ori", None), lambda pkt:pkt.type in [13,14]),
596f7d24e3fSHanoh Haim                    ConditionalField(ICMPTimeStampField("ts_rx", None), lambda pkt:pkt.type in [13,14]),
597f7d24e3fSHanoh Haim                    ConditionalField(ICMPTimeStampField("ts_tx", None), lambda pkt:pkt.type in [13,14]),
598f7d24e3fSHanoh Haim                    ConditionalField(IPField("gw","0.0.0.0"),  lambda pkt:pkt.type==5),
599f7d24e3fSHanoh Haim                    ConditionalField(ByteField("ptr",0),   lambda pkt:pkt.type==12),
600f7d24e3fSHanoh Haim                    ConditionalField(X3BytesField("reserved",0), lambda pkt:pkt.type==12),
601f7d24e3fSHanoh Haim                    ConditionalField(IPField("addr_mask","0.0.0.0"), lambda pkt:pkt.type in [17,18]),
602f7d24e3fSHanoh Haim                    ConditionalField(IntField("unused",0), lambda pkt:pkt.type not in [0,5,8,12,13,14,15,16,17,18]),
603f7d24e3fSHanoh Haim
604f7d24e3fSHanoh Haim                    ]
605f7d24e3fSHanoh Haim    def post_build(self, p, pay):
606f7d24e3fSHanoh Haim        p += pay
607f7d24e3fSHanoh Haim        if self.chksum is None:
608f7d24e3fSHanoh Haim            ck = checksum(p)
609f7d24e3fSHanoh Haim            p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:]
610f7d24e3fSHanoh Haim        return p
611f7d24e3fSHanoh Haim
612f7d24e3fSHanoh Haim    def hashret(self):
613f7d24e3fSHanoh Haim        if self.type in [0,8,13,14,15,16,17,18]:
614f7d24e3fSHanoh Haim            return struct.pack("HH",self.id,self.seq)+self.payload.hashret()
615f7d24e3fSHanoh Haim        return self.payload.hashret()
616f7d24e3fSHanoh Haim    def answers(self, other):
617f7d24e3fSHanoh Haim        if not isinstance(other,ICMP):
618f7d24e3fSHanoh Haim            return 0
619f7d24e3fSHanoh Haim        if ( (other.type,self.type) in [(8,0),(13,14),(15,16),(17,18)] and
620f7d24e3fSHanoh Haim             self.id == other.id and
621f7d24e3fSHanoh Haim             self.seq == other.seq ):
622f7d24e3fSHanoh Haim            return 1
623f7d24e3fSHanoh Haim        return 0
624f7d24e3fSHanoh Haim
625f7d24e3fSHanoh Haim    def guess_payload_class(self, payload):
626f7d24e3fSHanoh Haim        if self.type in [3,4,5,11,12]:
627f7d24e3fSHanoh Haim            return IPerror
628f7d24e3fSHanoh Haim        else:
629f7d24e3fSHanoh Haim            return None
630f7d24e3fSHanoh Haim    def mysummary(self):
631f7d24e3fSHanoh Haim        if isinstance(self.underlayer, IP):
632f7d24e3fSHanoh Haim            return self.underlayer.sprintf("ICMP %IP.src% > %IP.dst% %ICMP.type% %ICMP.code%")
633f7d24e3fSHanoh Haim        else:
634f7d24e3fSHanoh Haim            return self.sprintf("ICMP %ICMP.type% %ICMP.code%")
635f7d24e3fSHanoh Haim
636f7d24e3fSHanoh Haim
637f7d24e3fSHanoh Haim
638f7d24e3fSHanoh Haim
639f7d24e3fSHanoh Haim
640f7d24e3fSHanoh Haimclass IPerror(IP):
641f7d24e3fSHanoh Haim    name = "IP in ICMP"
642f7d24e3fSHanoh Haim    def answers(self, other):
643f7d24e3fSHanoh Haim        if not isinstance(other, IP):
644f7d24e3fSHanoh Haim            return 0
645f7d24e3fSHanoh Haim        if not ( ((conf.checkIPsrc == 0) or (self.dst == other.dst)) and
646f7d24e3fSHanoh Haim                 (self.src == other.src) and
647f7d24e3fSHanoh Haim                 ( ((conf.checkIPID == 0)
648f7d24e3fSHanoh Haim                    or (self.id == other.id)
649f7d24e3fSHanoh Haim                    or (conf.checkIPID == 1 and self.id == socket.htons(other.id)))) and
650f7d24e3fSHanoh Haim                 (self.proto == other.proto) ):
651f7d24e3fSHanoh Haim            return 0
652f7d24e3fSHanoh Haim        return self.payload.answers(other.payload)
653f7d24e3fSHanoh Haim    def mysummary(self):
654f7d24e3fSHanoh Haim        return Packet.mysummary(self)
655f7d24e3fSHanoh Haim
656f7d24e3fSHanoh Haim
657f7d24e3fSHanoh Haimclass TCPerror(TCP):
658f7d24e3fSHanoh Haim    name = "TCP in ICMP"
659f7d24e3fSHanoh Haim    def answers(self, other):
660f7d24e3fSHanoh Haim        if not isinstance(other, TCP):
661f7d24e3fSHanoh Haim            return 0
662f7d24e3fSHanoh Haim        if conf.checkIPsrc:
663f7d24e3fSHanoh Haim            if not ((self.sport == other.sport) and
664f7d24e3fSHanoh Haim                    (self.dport == other.dport)):
665f7d24e3fSHanoh Haim                return 0
666f7d24e3fSHanoh Haim        if conf.check_TCPerror_seqack:
667f7d24e3fSHanoh Haim            if self.seq is not None:
668f7d24e3fSHanoh Haim                if self.seq != other.seq:
669f7d24e3fSHanoh Haim                    return 0
670f7d24e3fSHanoh Haim            if self.ack is not None:
671f7d24e3fSHanoh Haim                if self.ack != other.ack:
672f7d24e3fSHanoh Haim                    return 0
673f7d24e3fSHanoh Haim        return 1
674f7d24e3fSHanoh Haim    def mysummary(self):
675f7d24e3fSHanoh Haim        return Packet.mysummary(self)
676f7d24e3fSHanoh Haim
677f7d24e3fSHanoh Haim
678f7d24e3fSHanoh Haimclass UDPerror(UDP):
679f7d24e3fSHanoh Haim    name = "UDP in ICMP"
680f7d24e3fSHanoh Haim    def answers(self, other):
681f7d24e3fSHanoh Haim        if not isinstance(other, UDP):
682f7d24e3fSHanoh Haim            return 0
683f7d24e3fSHanoh Haim        if conf.checkIPsrc:
684f7d24e3fSHanoh Haim            if not ((self.sport == other.sport) and
685f7d24e3fSHanoh Haim                    (self.dport == other.dport)):
686f7d24e3fSHanoh Haim                return 0
687f7d24e3fSHanoh Haim        return 1
688f7d24e3fSHanoh Haim    def mysummary(self):
689f7d24e3fSHanoh Haim        return Packet.mysummary(self)
690f7d24e3fSHanoh Haim
691f7d24e3fSHanoh Haim
692f7d24e3fSHanoh Haim
693f7d24e3fSHanoh Haimclass ICMPerror(ICMP):
694f7d24e3fSHanoh Haim    name = "ICMP in ICMP"
695f7d24e3fSHanoh Haim    def answers(self, other):
696f7d24e3fSHanoh Haim        if not isinstance(other,ICMP):
697f7d24e3fSHanoh Haim            return 0
698f7d24e3fSHanoh Haim        if not ((self.type == other.type) and
699f7d24e3fSHanoh Haim                (self.code == other.code)):
700f7d24e3fSHanoh Haim            return 0
701f7d24e3fSHanoh Haim        if self.code in [0,8,13,14,17,18]:
702f7d24e3fSHanoh Haim            if (self.id == other.id and
703f7d24e3fSHanoh Haim                self.seq == other.seq):
704f7d24e3fSHanoh Haim                return 1
705f7d24e3fSHanoh Haim            else:
706f7d24e3fSHanoh Haim                return 0
707f7d24e3fSHanoh Haim        else:
708f7d24e3fSHanoh Haim            return 1
709f7d24e3fSHanoh Haim    def mysummary(self):
710f7d24e3fSHanoh Haim        return Packet.mysummary(self)
711f7d24e3fSHanoh Haim
712f7d24e3fSHanoh Haimbind_layers( Ether,         IP,            type=2048)
713f7d24e3fSHanoh Haimbind_layers( CookedLinux,   IP,            proto=2048)
714f7d24e3fSHanoh Haimbind_layers( GRE,           IP,            proto=2048)
715f7d24e3fSHanoh Haimbind_layers( SNAP,          IP,            code=2048)
716f7d24e3fSHanoh Haimbind_layers( IPerror,       IPerror,       frag=0, proto=4)
717f7d24e3fSHanoh Haimbind_layers( IPerror,       ICMPerror,     frag=0, proto=1)
718f7d24e3fSHanoh Haimbind_layers( IPerror,       TCPerror,      frag=0, proto=6)
719f7d24e3fSHanoh Haimbind_layers( IPerror,       UDPerror,      frag=0, proto=17)
720f7d24e3fSHanoh Haimbind_layers( IP,            IP,            frag=0, proto=4)
721f7d24e3fSHanoh Haimbind_layers( IP,            ICMP,          frag=0, proto=1)
722f7d24e3fSHanoh Haimbind_layers( IP,            TCP,           frag=0, proto=6)
723f7d24e3fSHanoh Haimbind_layers( IP,            UDP,           frag=0, proto=17)
724f7d24e3fSHanoh Haimbind_layers( IP,            GRE,           frag=0, proto=47)
725f7d24e3fSHanoh Haim
726f7d24e3fSHanoh Haimconf.l2types.register(101, IP)
727f7d24e3fSHanoh Haimconf.l2types.register_num2layer(12, IP)
728f7d24e3fSHanoh Haim
729f7d24e3fSHanoh Haimconf.l3types.register(ETH_P_IP, IP)
730f7d24e3fSHanoh Haimconf.l3types.register_num2layer(ETH_P_ALL, IP)
731f7d24e3fSHanoh Haim
732f7d24e3fSHanoh Haim
733f7d24e3fSHanoh Haimconf.neighbor.register_l3(Ether, IP, lambda l2,l3: getmacbyip(l3.dst))
734f7d24e3fSHanoh Haimconf.neighbor.register_l3(Dot3, IP, lambda l2,l3: getmacbyip(l3.dst))
735f7d24e3fSHanoh Haim
736f7d24e3fSHanoh Haim
737f7d24e3fSHanoh Haim###################
738f7d24e3fSHanoh Haim## Fragmentation ##
739f7d24e3fSHanoh Haim###################
740f7d24e3fSHanoh Haim
741f7d24e3fSHanoh Haim@conf.commands.register
742f7d24e3fSHanoh Haimdef fragment(pkt, fragsize=1480):
743f7d24e3fSHanoh Haim    """Fragment a big IP datagram"""
744f7d24e3fSHanoh Haim    fragsize = (fragsize+7)/8*8
745f7d24e3fSHanoh Haim    lst = []
746f7d24e3fSHanoh Haim    for p in pkt:
747f7d24e3fSHanoh Haim        s = str(p[IP].payload)
748f7d24e3fSHanoh Haim        nb = (len(s)+fragsize-1)/fragsize
749f7d24e3fSHanoh Haim        for i in range(nb):
750f7d24e3fSHanoh Haim            q = p.copy()
751f7d24e3fSHanoh Haim            del(q[IP].payload)
752f7d24e3fSHanoh Haim            del(q[IP].chksum)
753f7d24e3fSHanoh Haim            del(q[IP].len)
754f7d24e3fSHanoh Haim            if i == nb-1:
755f7d24e3fSHanoh Haim                q[IP].flags &= ~1
756f7d24e3fSHanoh Haim            else:
757f7d24e3fSHanoh Haim                q[IP].flags |= 1
758f7d24e3fSHanoh Haim            q[IP].frag = i*fragsize/8
759f7d24e3fSHanoh Haim            r = conf.raw_layer(load=s[i*fragsize:(i+1)*fragsize])
760f7d24e3fSHanoh Haim            r.overload_fields = p[IP].payload.overload_fields.copy()
761f7d24e3fSHanoh Haim            q.add_payload(r)
762f7d24e3fSHanoh Haim            lst.append(q)
763f7d24e3fSHanoh Haim    return lst
764f7d24e3fSHanoh Haim
765f7d24e3fSHanoh Haimdef overlap_frag(p, overlap, fragsize=8, overlap_fragsize=None):
766f7d24e3fSHanoh Haim    if overlap_fragsize is None:
767f7d24e3fSHanoh Haim        overlap_fragsize = fragsize
768f7d24e3fSHanoh Haim    q = p.copy()
769f7d24e3fSHanoh Haim    del(q[IP].payload)
770f7d24e3fSHanoh Haim    q[IP].add_payload(overlap)
771f7d24e3fSHanoh Haim
772f7d24e3fSHanoh Haim    qfrag = fragment(q, overlap_fragsize)
773f7d24e3fSHanoh Haim    qfrag[-1][IP].flags |= 1
774f7d24e3fSHanoh Haim    return qfrag+fragment(p, fragsize)
775f7d24e3fSHanoh Haim
776f7d24e3fSHanoh Haim@conf.commands.register
777f7d24e3fSHanoh Haimdef defrag(plist):
778f7d24e3fSHanoh Haim    """defrag(plist) -> ([not fragmented], [defragmented],
779f7d24e3fSHanoh Haim                  [ [bad fragments], [bad fragments], ... ])"""
780f7d24e3fSHanoh Haim    frags = defaultdict(PacketList)
781f7d24e3fSHanoh Haim    nofrag = PacketList()
782f7d24e3fSHanoh Haim    for p in plist:
783f7d24e3fSHanoh Haim        ip = p[IP]
784f7d24e3fSHanoh Haim        if IP not in p:
785f7d24e3fSHanoh Haim            nofrag.append(p)
786f7d24e3fSHanoh Haim            continue
787f7d24e3fSHanoh Haim        if ip.frag == 0 and ip.flags & 1 == 0:
788f7d24e3fSHanoh Haim            nofrag.append(p)
789f7d24e3fSHanoh Haim            continue
790f7d24e3fSHanoh Haim        uniq = (ip.id,ip.src,ip.dst,ip.proto)
791f7d24e3fSHanoh Haim        frags[uniq].append(p)
792f7d24e3fSHanoh Haim    defrag = []
793f7d24e3fSHanoh Haim    missfrag = []
794f7d24e3fSHanoh Haim    for lst in frags.itervalues():
795f7d24e3fSHanoh Haim        lst.sort(key=lambda x: x.frag)
796f7d24e3fSHanoh Haim        p = lst[0]
797f7d24e3fSHanoh Haim        lastp = lst[-1]
798f7d24e3fSHanoh Haim        if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing
799f7d24e3fSHanoh Haim            missfrag.append(lst)
800f7d24e3fSHanoh Haim            continue
801f7d24e3fSHanoh Haim        p = p.copy()
802f7d24e3fSHanoh Haim        if conf.padding_layer in p:
803f7d24e3fSHanoh Haim            del(p[conf.padding_layer].underlayer.payload)
804f7d24e3fSHanoh Haim        ip = p[IP]
805f7d24e3fSHanoh Haim        if ip.len is None or ip.ihl is None:
806f7d24e3fSHanoh Haim            clen = len(ip.payload)
807f7d24e3fSHanoh Haim        else:
808f7d24e3fSHanoh Haim            clen = ip.len - (ip.ihl<<2)
809f7d24e3fSHanoh Haim        txt = conf.raw_layer()
810f7d24e3fSHanoh Haim        for q in lst[1:]:
811f7d24e3fSHanoh Haim            if clen != q.frag<<3: # Wrong fragmentation offset
812f7d24e3fSHanoh Haim                if clen > q.frag<<3:
813f7d24e3fSHanoh Haim                    warning("Fragment overlap (%i > %i) %r || %r ||  %r" % (clen, q.frag<<3, p,txt,q))
814f7d24e3fSHanoh Haim                missfrag.append(lst)
815f7d24e3fSHanoh Haim                break
816f7d24e3fSHanoh Haim            if q[IP].len is None or q[IP].ihl is None:
817f7d24e3fSHanoh Haim                clen += len(q[IP].payload)
818f7d24e3fSHanoh Haim            else:
819f7d24e3fSHanoh Haim                clen += q[IP].len - (q[IP].ihl<<2)
820f7d24e3fSHanoh Haim            if conf.padding_layer in q:
821f7d24e3fSHanoh Haim                del(q[conf.padding_layer].underlayer.payload)
822f7d24e3fSHanoh Haim            txt.add_payload(q[IP].payload.copy())
823f7d24e3fSHanoh Haim        else:
824f7d24e3fSHanoh Haim            ip.flags &= ~1 # !MF
825f7d24e3fSHanoh Haim            del(ip.chksum)
826f7d24e3fSHanoh Haim            del(ip.len)
827f7d24e3fSHanoh Haim            p = p/txt
828f7d24e3fSHanoh Haim            defrag.append(p)
829f7d24e3fSHanoh Haim    defrag2=PacketList()
830f7d24e3fSHanoh Haim    for p in defrag:
831f7d24e3fSHanoh Haim        defrag2.append(p.__class__(str(p)))
832f7d24e3fSHanoh Haim    return nofrag,defrag2,missfrag
833f7d24e3fSHanoh Haim
834f7d24e3fSHanoh Haim@conf.commands.register
835f7d24e3fSHanoh Haimdef defragment(plist):
836f7d24e3fSHanoh Haim    """defrag(plist) -> plist defragmented as much as possible """
837f7d24e3fSHanoh Haim    frags = defaultdict(lambda:[])
838f7d24e3fSHanoh Haim    final = []
839f7d24e3fSHanoh Haim
840f7d24e3fSHanoh Haim    pos = 0
841f7d24e3fSHanoh Haim    for p in plist:
842f7d24e3fSHanoh Haim        p._defrag_pos = pos
843f7d24e3fSHanoh Haim        pos += 1
844f7d24e3fSHanoh Haim        if IP in p:
845f7d24e3fSHanoh Haim            ip = p[IP]
846f7d24e3fSHanoh Haim            if ip.frag != 0 or ip.flags & 1:
847f7d24e3fSHanoh Haim                ip = p[IP]
848f7d24e3fSHanoh Haim                uniq = (ip.id,ip.src,ip.dst,ip.proto)
849f7d24e3fSHanoh Haim                frags[uniq].append(p)
850f7d24e3fSHanoh Haim                continue
851f7d24e3fSHanoh Haim        final.append(p)
852f7d24e3fSHanoh Haim
853f7d24e3fSHanoh Haim    defrag = []
854f7d24e3fSHanoh Haim    missfrag = []
855f7d24e3fSHanoh Haim    for lst in frags.itervalues():
856f7d24e3fSHanoh Haim        lst.sort(key=lambda x: x.frag)
857f7d24e3fSHanoh Haim        p = lst[0]
858f7d24e3fSHanoh Haim        lastp = lst[-1]
859f7d24e3fSHanoh Haim        if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing
860f7d24e3fSHanoh Haim            missfrag += lst
861f7d24e3fSHanoh Haim            continue
862f7d24e3fSHanoh Haim        p = p.copy()
863f7d24e3fSHanoh Haim        if conf.padding_layer in p:
864f7d24e3fSHanoh Haim            del(p[conf.padding_layer].underlayer.payload)
865f7d24e3fSHanoh Haim        ip = p[IP]
866f7d24e3fSHanoh Haim        if ip.len is None or ip.ihl is None:
867f7d24e3fSHanoh Haim            clen = len(ip.payload)
868f7d24e3fSHanoh Haim        else:
869f7d24e3fSHanoh Haim            clen = ip.len - (ip.ihl<<2)
870f7d24e3fSHanoh Haim        txt = conf.raw_layer()
871f7d24e3fSHanoh Haim        for q in lst[1:]:
872f7d24e3fSHanoh Haim            if clen != q.frag<<3: # Wrong fragmentation offset
873f7d24e3fSHanoh Haim                if clen > q.frag<<3:
874f7d24e3fSHanoh Haim                    warning("Fragment overlap (%i > %i) %r || %r ||  %r" % (clen, q.frag<<3, p,txt,q))
875f7d24e3fSHanoh Haim                missfrag += lst
876f7d24e3fSHanoh Haim                break
877f7d24e3fSHanoh Haim            if q[IP].len is None or q[IP].ihl is None:
878f7d24e3fSHanoh Haim                clen += len(q[IP].payload)
879f7d24e3fSHanoh Haim            else:
880f7d24e3fSHanoh Haim                clen += q[IP].len - (q[IP].ihl<<2)
881f7d24e3fSHanoh Haim            if conf.padding_layer in q:
882f7d24e3fSHanoh Haim                del(q[conf.padding_layer].underlayer.payload)
883f7d24e3fSHanoh Haim            txt.add_payload(q[IP].payload.copy())
884f7d24e3fSHanoh Haim        else:
885f7d24e3fSHanoh Haim            ip.flags &= ~1 # !MF
886f7d24e3fSHanoh Haim            del(ip.chksum)
887f7d24e3fSHanoh Haim            del(ip.len)
888f7d24e3fSHanoh Haim            p = p/txt
889f7d24e3fSHanoh Haim            p._defrag_pos = max(x._defrag_pos for x in lst)
890f7d24e3fSHanoh Haim            defrag.append(p)
891f7d24e3fSHanoh Haim    defrag2=[]
892f7d24e3fSHanoh Haim    for p in defrag:
893f7d24e3fSHanoh Haim        q = p.__class__(str(p))
894f7d24e3fSHanoh Haim        q._defrag_pos = p._defrag_pos
895f7d24e3fSHanoh Haim        defrag2.append(q)
896f7d24e3fSHanoh Haim    final += defrag2
897f7d24e3fSHanoh Haim    final += missfrag
898f7d24e3fSHanoh Haim    final.sort(key=lambda x: x._defrag_pos)
899f7d24e3fSHanoh Haim    for p in final:
900f7d24e3fSHanoh Haim        del(p._defrag_pos)
901f7d24e3fSHanoh Haim
902f7d24e3fSHanoh Haim    if hasattr(plist, "listname"):
903f7d24e3fSHanoh Haim        name = "Defragmented %s" % plist.listname
904f7d24e3fSHanoh Haim    else:
905f7d24e3fSHanoh Haim        name = "Defragmented"
906f7d24e3fSHanoh Haim
907f7d24e3fSHanoh Haim    return PacketList(final, name=name)
908f7d24e3fSHanoh Haim
909f7d24e3fSHanoh Haim
910f7d24e3fSHanoh Haim
911f7d24e3fSHanoh Haim### Add timeskew_graph() method to PacketList
912f7d24e3fSHanoh Haimdef _packetlist_timeskew_graph(self, ip, **kargs):
913f7d24e3fSHanoh Haim    """Tries to graph the timeskew between the timestamps and real time for a given ip"""
914f7d24e3fSHanoh Haim    res = map(lambda x: self._elt2pkt(x), self.res)
915f7d24e3fSHanoh Haim    b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res)
916f7d24e3fSHanoh Haim    c = []
917f7d24e3fSHanoh Haim    for p in b:
918f7d24e3fSHanoh Haim        opts = p.getlayer(TCP).options
919f7d24e3fSHanoh Haim        for o in opts:
920f7d24e3fSHanoh Haim            if o[0] == "Timestamp":
921f7d24e3fSHanoh Haim                c.append((p.time,o[1][0]))
922f7d24e3fSHanoh Haim    if not c:
923f7d24e3fSHanoh Haim        warning("No timestamps found in packet list")
924f7d24e3fSHanoh Haim        return
925f7d24e3fSHanoh Haim    d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c)
926f7d24e3fSHanoh Haim    g = Gnuplot.Gnuplot()
927f7d24e3fSHanoh Haim    g.plot(Gnuplot.Data(d,**kargs))
928f7d24e3fSHanoh Haim    return g
929f7d24e3fSHanoh Haim
930f7d24e3fSHanoh HaimPacketList.timeskew_graph = new.instancemethod(_packetlist_timeskew_graph, None, PacketList)
931f7d24e3fSHanoh Haim
932f7d24e3fSHanoh Haim
933f7d24e3fSHanoh Haim### Create a new packet list
934f7d24e3fSHanoh Haimclass TracerouteResult(SndRcvList):
935f7d24e3fSHanoh Haim    def __init__(self, res=None, name="Traceroute", stats=None):
936f7d24e3fSHanoh Haim        PacketList.__init__(self, res, name, stats)
937f7d24e3fSHanoh Haim        self.graphdef = None
938f7d24e3fSHanoh Haim        self.graphASres = 0
939f7d24e3fSHanoh Haim        self.padding = 0
940f7d24e3fSHanoh Haim        self.hloc = None
941f7d24e3fSHanoh Haim        self.nloc = None
942f7d24e3fSHanoh Haim
943f7d24e3fSHanoh Haim    def show(self):
944f7d24e3fSHanoh Haim        return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),
945f7d24e3fSHanoh Haim                                              s.ttl,
946f7d24e3fSHanoh Haim                                              r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}")))
947f7d24e3fSHanoh Haim
948f7d24e3fSHanoh Haim
949f7d24e3fSHanoh Haim    def get_trace(self):
950f7d24e3fSHanoh Haim        trace = {}
951f7d24e3fSHanoh Haim        for s,r in self.res:
952f7d24e3fSHanoh Haim            if IP not in s:
953f7d24e3fSHanoh Haim                continue
954f7d24e3fSHanoh Haim            d = s[IP].dst
955f7d24e3fSHanoh Haim            if d not in trace:
956f7d24e3fSHanoh Haim                trace[d] = {}
957f7d24e3fSHanoh Haim            trace[d][s[IP].ttl] = r[IP].src, ICMP not in r
958f7d24e3fSHanoh Haim        for k in trace.values():
959f7d24e3fSHanoh Haim            m = filter(lambda x:k[x][1], k.keys())
960f7d24e3fSHanoh Haim            if not m:
961f7d24e3fSHanoh Haim                continue
962f7d24e3fSHanoh Haim            m = min(m)
963f7d24e3fSHanoh Haim            for l in k.keys():
964f7d24e3fSHanoh Haim                if l > m:
965f7d24e3fSHanoh Haim                    del(k[l])
966f7d24e3fSHanoh Haim        return trace
967f7d24e3fSHanoh Haim
968f7d24e3fSHanoh Haim    def trace3D(self):
969f7d24e3fSHanoh Haim        """Give a 3D representation of the traceroute.
970f7d24e3fSHanoh Haim        right button: rotate the scene
971f7d24e3fSHanoh Haim        middle button: zoom
972f7d24e3fSHanoh Haim        left button: move the scene
973f7d24e3fSHanoh Haim        left button on a ball: toggle IP displaying
974f7d24e3fSHanoh Haim        ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result"""
975f7d24e3fSHanoh Haim        trace = self.get_trace()
976f7d24e3fSHanoh Haim        import visual
977f7d24e3fSHanoh Haim
978f7d24e3fSHanoh Haim        class IPsphere(visual.sphere):
979f7d24e3fSHanoh Haim            def __init__(self, ip, **kargs):
980f7d24e3fSHanoh Haim                visual.sphere.__init__(self, **kargs)
981f7d24e3fSHanoh Haim                self.ip=ip
982f7d24e3fSHanoh Haim                self.label=None
983f7d24e3fSHanoh Haim                self.setlabel(self.ip)
984f7d24e3fSHanoh Haim            def setlabel(self, txt,visible=None):
985f7d24e3fSHanoh Haim                if self.label is not None:
986f7d24e3fSHanoh Haim                    if visible is None:
987f7d24e3fSHanoh Haim                        visible = self.label.visible
988f7d24e3fSHanoh Haim                    self.label.visible = 0
989f7d24e3fSHanoh Haim                elif visible is None:
990f7d24e3fSHanoh Haim                    visible=0
991f7d24e3fSHanoh Haim                self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible)
992f7d24e3fSHanoh Haim            def action(self):
993f7d24e3fSHanoh Haim                self.label.visible ^= 1
994f7d24e3fSHanoh Haim
995f7d24e3fSHanoh Haim        visual.scene = visual.display()
996f7d24e3fSHanoh Haim        visual.scene.exit = True
997f7d24e3fSHanoh Haim        start = visual.box()
998f7d24e3fSHanoh Haim        rings={}
999f7d24e3fSHanoh Haim        tr3d = {}
1000f7d24e3fSHanoh Haim        for i in trace:
1001f7d24e3fSHanoh Haim            tr = trace[i]
1002f7d24e3fSHanoh Haim            tr3d[i] = []
1003f7d24e3fSHanoh Haim            ttl = tr.keys()
1004f7d24e3fSHanoh Haim            for t in range(1,max(ttl)+1):
1005f7d24e3fSHanoh Haim                if t not in rings:
1006f7d24e3fSHanoh Haim                    rings[t] = []
1007f7d24e3fSHanoh Haim                if t in tr:
1008f7d24e3fSHanoh Haim                    if tr[t] not in rings[t]:
1009f7d24e3fSHanoh Haim                        rings[t].append(tr[t])
1010f7d24e3fSHanoh Haim                    tr3d[i].append(rings[t].index(tr[t]))
1011f7d24e3fSHanoh Haim                else:
1012f7d24e3fSHanoh Haim                    rings[t].append(("unk",-1))
1013f7d24e3fSHanoh Haim                    tr3d[i].append(len(rings[t])-1)
1014f7d24e3fSHanoh Haim        for t in rings:
1015f7d24e3fSHanoh Haim            r = rings[t]
1016f7d24e3fSHanoh Haim            l = len(r)
1017f7d24e3fSHanoh Haim            for i in range(l):
1018f7d24e3fSHanoh Haim                if r[i][1] == -1:
1019f7d24e3fSHanoh Haim                    col = (0.75,0.75,0.75)
1020f7d24e3fSHanoh Haim                elif r[i][1]:
1021f7d24e3fSHanoh Haim                    col = visual.color.green
1022f7d24e3fSHanoh Haim                else:
1023f7d24e3fSHanoh Haim                    col = visual.color.blue
1024f7d24e3fSHanoh Haim
1025f7d24e3fSHanoh Haim                s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t),
1026f7d24e3fSHanoh Haim                             ip = r[i][0],
1027f7d24e3fSHanoh Haim                             color = col)
1028f7d24e3fSHanoh Haim                for trlst in tr3d.values():
1029f7d24e3fSHanoh Haim                    if t <= len(trlst):
1030f7d24e3fSHanoh Haim                        if trlst[t-1] == i:
1031f7d24e3fSHanoh Haim                            trlst[t-1] = s
1032f7d24e3fSHanoh Haim        forecol = colgen(0.625, 0.4375, 0.25, 0.125)
1033f7d24e3fSHanoh Haim        for trlst in tr3d.values():
1034f7d24e3fSHanoh Haim            col = forecol.next()
1035f7d24e3fSHanoh Haim            start = (0,0,0)
1036f7d24e3fSHanoh Haim            for ip in trlst:
1037f7d24e3fSHanoh Haim                visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2)
1038f7d24e3fSHanoh Haim                start = ip.pos
1039f7d24e3fSHanoh Haim
1040f7d24e3fSHanoh Haim        movcenter=None
1041f7d24e3fSHanoh Haim        while 1:
1042f7d24e3fSHanoh Haim            visual.rate(50)
1043f7d24e3fSHanoh Haim            if visual.scene.kb.keys:
1044f7d24e3fSHanoh Haim                k = visual.scene.kb.getkey()
1045f7d24e3fSHanoh Haim                if k == "esc" or k == "q":
1046f7d24e3fSHanoh Haim                    break
1047f7d24e3fSHanoh Haim            if visual.scene.mouse.events:
1048f7d24e3fSHanoh Haim                ev = visual.scene.mouse.getevent()
1049f7d24e3fSHanoh Haim                if ev.press == "left":
1050f7d24e3fSHanoh Haim                    o = ev.pick
1051f7d24e3fSHanoh Haim                    if o:
1052f7d24e3fSHanoh Haim                        if ev.ctrl:
1053f7d24e3fSHanoh Haim                            if o.ip == "unk":
1054f7d24e3fSHanoh Haim                                continue
1055f7d24e3fSHanoh Haim                            savcolor = o.color
1056f7d24e3fSHanoh Haim                            o.color = (1,0,0)
1057f7d24e3fSHanoh Haim                            a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2)
1058f7d24e3fSHanoh Haim                            o.color = savcolor
1059f7d24e3fSHanoh Haim                            if len(a) == 0:
1060f7d24e3fSHanoh Haim                                txt = "%s:\nno results" % o.ip
1061f7d24e3fSHanoh Haim                            else:
1062f7d24e3fSHanoh Haim                                txt = "%s:\n" % o.ip
1063f7d24e3fSHanoh Haim                                for s,r in a:
1064f7d24e3fSHanoh Haim                                    txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n")
1065f7d24e3fSHanoh Haim                            o.setlabel(txt, visible=1)
1066f7d24e3fSHanoh Haim                        else:
1067f7d24e3fSHanoh Haim                            if hasattr(o, "action"):
1068f7d24e3fSHanoh Haim                                o.action()
1069f7d24e3fSHanoh Haim                elif ev.drag == "left":
1070f7d24e3fSHanoh Haim                    movcenter = ev.pos
1071f7d24e3fSHanoh Haim                elif ev.drop == "left":
1072f7d24e3fSHanoh Haim                    movcenter = None
1073f7d24e3fSHanoh Haim            if movcenter:
1074f7d24e3fSHanoh Haim                visual.scene.center -= visual.scene.mouse.pos-movcenter
1075f7d24e3fSHanoh Haim                movcenter = visual.scene.mouse.pos
1076f7d24e3fSHanoh Haim
1077f7d24e3fSHanoh Haim
1078f7d24e3fSHanoh Haim    def world_trace(self):
1079f7d24e3fSHanoh Haim        from modules.geo import locate_ip
1080f7d24e3fSHanoh Haim        ips = {}
1081f7d24e3fSHanoh Haim        rt = {}
1082f7d24e3fSHanoh Haim        ports_done = {}
1083f7d24e3fSHanoh Haim        for s,r in self.res:
1084f7d24e3fSHanoh Haim            ips[r.src] = None
1085f7d24e3fSHanoh Haim            if s.haslayer(TCP) or s.haslayer(UDP):
1086f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,s.proto,s.dport)
1087f7d24e3fSHanoh Haim            elif s.haslayer(ICMP):
1088f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,s.proto,s.type)
1089f7d24e3fSHanoh Haim            else:
1090f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,s.proto,0)
1091f7d24e3fSHanoh Haim            trace = rt.get(trace_id,{})
1092f7d24e3fSHanoh Haim            if not r.haslayer(ICMP) or r.type != 11:
1093f7d24e3fSHanoh Haim                if ports_done.has_key(trace_id):
1094f7d24e3fSHanoh Haim                    continue
1095f7d24e3fSHanoh Haim                ports_done[trace_id] = None
1096f7d24e3fSHanoh Haim            trace[s.ttl] = r.src
1097f7d24e3fSHanoh Haim            rt[trace_id] = trace
1098f7d24e3fSHanoh Haim
1099f7d24e3fSHanoh Haim        trt = {}
1100f7d24e3fSHanoh Haim        for trace_id in rt:
1101f7d24e3fSHanoh Haim            trace = rt[trace_id]
1102f7d24e3fSHanoh Haim            loctrace = []
1103f7d24e3fSHanoh Haim            for i in range(max(trace.keys())):
1104f7d24e3fSHanoh Haim                ip = trace.get(i,None)
1105f7d24e3fSHanoh Haim                if ip is None:
1106f7d24e3fSHanoh Haim                    continue
1107f7d24e3fSHanoh Haim                loc = locate_ip(ip)
1108f7d24e3fSHanoh Haim                if loc is None:
1109f7d24e3fSHanoh Haim                    continue
1110f7d24e3fSHanoh Haim#                loctrace.append((ip,loc)) # no labels yet
1111f7d24e3fSHanoh Haim                loctrace.append(loc)
1112f7d24e3fSHanoh Haim            if loctrace:
1113f7d24e3fSHanoh Haim                trt[trace_id] = loctrace
1114f7d24e3fSHanoh Haim
1115f7d24e3fSHanoh Haim        tr = map(lambda x: Gnuplot.Data(x,with_="lines"), trt.values())
1116f7d24e3fSHanoh Haim        g = Gnuplot.Gnuplot()
1117f7d24e3fSHanoh Haim        world = Gnuplot.File(conf.gnuplot_world,with_="lines")
1118f7d24e3fSHanoh Haim        g.plot(world,*tr)
1119f7d24e3fSHanoh Haim        return g
1120f7d24e3fSHanoh Haim
1121f7d24e3fSHanoh Haim    def make_graph(self,ASres=None,padding=0):
1122f7d24e3fSHanoh Haim        if ASres is None:
1123f7d24e3fSHanoh Haim            ASres = conf.AS_resolver
1124f7d24e3fSHanoh Haim        self.graphASres = ASres
1125f7d24e3fSHanoh Haim        self.graphpadding = padding
1126f7d24e3fSHanoh Haim        ips = {}
1127f7d24e3fSHanoh Haim        rt = {}
1128f7d24e3fSHanoh Haim        ports = {}
1129f7d24e3fSHanoh Haim        ports_done = {}
1130f7d24e3fSHanoh Haim        for s,r in self.res:
1131f7d24e3fSHanoh Haim            r = r.getlayer(IP) or (conf.ipv6_enabled and r[scapy.layers.inet6.IPv6]) or r
1132f7d24e3fSHanoh Haim            s = s.getlayer(IP) or (conf.ipv6_enabled and s[scapy.layers.inet6.IPv6]) or s
1133f7d24e3fSHanoh Haim            ips[r.src] = None
1134f7d24e3fSHanoh Haim            if TCP in s:
1135f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,6,s.dport)
1136f7d24e3fSHanoh Haim            elif UDP in s:
1137f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,17,s.dport)
1138f7d24e3fSHanoh Haim            elif ICMP in s:
1139f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,1,s.type)
1140f7d24e3fSHanoh Haim            else:
1141f7d24e3fSHanoh Haim                trace_id = (s.src,s.dst,s.proto,0)
1142f7d24e3fSHanoh Haim            trace = rt.get(trace_id,{})
1143f7d24e3fSHanoh Haim            ttl = conf.ipv6_enabled and scapy.layers.inet6.IPv6 in s and s.hlim or s.ttl
1144f7d24e3fSHanoh Haim            if not (ICMP in r and r[ICMP].type == 11) and not (conf.ipv6_enabled and scapy.layers.inet6.IPv6 in r and scapy.layers.inet6.ICMPv6TimeExceeded in r):
1145f7d24e3fSHanoh Haim                if trace_id in ports_done:
1146f7d24e3fSHanoh Haim                    continue
1147f7d24e3fSHanoh Haim                ports_done[trace_id] = None
1148f7d24e3fSHanoh Haim                p = ports.get(r.src,[])
1149f7d24e3fSHanoh Haim                if TCP in r:
1150f7d24e3fSHanoh Haim                    p.append(r.sprintf("<T%ir,TCP.sport%> %TCP.sport% %TCP.flags%"))
1151f7d24e3fSHanoh Haim                    trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%')
1152f7d24e3fSHanoh Haim                elif UDP in r:
1153f7d24e3fSHanoh Haim                    p.append(r.sprintf("<U%ir,UDP.sport%> %UDP.sport%"))
1154f7d24e3fSHanoh Haim                    trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%')
1155f7d24e3fSHanoh Haim                elif ICMP in r:
1156f7d24e3fSHanoh Haim                    p.append(r.sprintf("<I%ir,ICMP.type%> ICMP %ICMP.type%"))
1157f7d24e3fSHanoh Haim                    trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%')
1158f7d24e3fSHanoh Haim                else:
1159f7d24e3fSHanoh Haim                    p.append(r.sprintf("{IP:<P%ir,proto%> IP %proto%}{IPv6:<P%ir,nh%> IPv6 %nh%}"))
1160f7d24e3fSHanoh Haim                    trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}')
1161f7d24e3fSHanoh Haim                ports[r.src] = p
1162f7d24e3fSHanoh Haim            else:
1163f7d24e3fSHanoh Haim                trace[ttl] = r.sprintf('"%r,src%"')
1164f7d24e3fSHanoh Haim            rt[trace_id] = trace
1165f7d24e3fSHanoh Haim
1166f7d24e3fSHanoh Haim        # Fill holes with unk%i nodes
1167f7d24e3fSHanoh Haim        unknown_label = incremental_label("unk%i")
1168f7d24e3fSHanoh Haim        blackholes = []
1169f7d24e3fSHanoh Haim        bhip = {}
1170f7d24e3fSHanoh Haim        for rtk in rt:
1171f7d24e3fSHanoh Haim            trace = rt[rtk]
1172f7d24e3fSHanoh Haim            k = trace.keys()
1173f7d24e3fSHanoh Haim            for n in range(min(k), max(k)):
1174f7d24e3fSHanoh Haim                if not trace.has_key(n):
1175f7d24e3fSHanoh Haim                    trace[n] = unknown_label.next()
1176f7d24e3fSHanoh Haim            if not ports_done.has_key(rtk):
1177f7d24e3fSHanoh Haim                if rtk[2] == 1: #ICMP
1178f7d24e3fSHanoh Haim                    bh = "%s %i/icmp" % (rtk[1],rtk[3])
1179f7d24e3fSHanoh Haim                elif rtk[2] == 6: #TCP
1180f7d24e3fSHanoh Haim                    bh = "%s %i/tcp" % (rtk[1],rtk[3])
1181f7d24e3fSHanoh Haim                elif rtk[2] == 17: #UDP
1182f7d24e3fSHanoh Haim                    bh = '%s %i/udp' % (rtk[1],rtk[3])
1183f7d24e3fSHanoh Haim                else:
1184f7d24e3fSHanoh Haim                    bh = '%s %i/proto' % (rtk[1],rtk[2])
1185f7d24e3fSHanoh Haim                ips[bh] = None
1186f7d24e3fSHanoh Haim                bhip[rtk[1]] = bh
1187f7d24e3fSHanoh Haim                bh = '"%s"' % bh
1188f7d24e3fSHanoh Haim                trace[max(k)+1] = bh
1189f7d24e3fSHanoh Haim                blackholes.append(bh)
1190f7d24e3fSHanoh Haim
1191f7d24e3fSHanoh Haim        # Find AS numbers
1192f7d24e3fSHanoh Haim        ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys()
1193f7d24e3fSHanoh Haim        if ASres is None:
1194f7d24e3fSHanoh Haim            ASNlist = []
1195f7d24e3fSHanoh Haim        else:
1196f7d24e3fSHanoh Haim            ASNlist = ASres.resolve(*ASN_query_list)
1197f7d24e3fSHanoh Haim
1198f7d24e3fSHanoh Haim        ASNs = {}
1199f7d24e3fSHanoh Haim        ASDs = {}
1200f7d24e3fSHanoh Haim        for ip,asn,desc, in ASNlist:
1201f7d24e3fSHanoh Haim            if asn is None:
1202f7d24e3fSHanoh Haim                continue
1203f7d24e3fSHanoh Haim            iplist = ASNs.get(asn,[])
1204f7d24e3fSHanoh Haim            if ip in bhip:
1205f7d24e3fSHanoh Haim                if ip in ports:
1206f7d24e3fSHanoh Haim                    iplist.append(ip)
1207f7d24e3fSHanoh Haim                iplist.append(bhip[ip])
1208f7d24e3fSHanoh Haim            else:
1209f7d24e3fSHanoh Haim                iplist.append(ip)
1210f7d24e3fSHanoh Haim            ASNs[asn] = iplist
1211f7d24e3fSHanoh Haim            ASDs[asn] = desc
1212f7d24e3fSHanoh Haim
1213f7d24e3fSHanoh Haim
1214f7d24e3fSHanoh Haim        backcolorlist=colgen("60","86","ba","ff")
1215f7d24e3fSHanoh Haim        forecolorlist=colgen("a0","70","40","20")
1216f7d24e3fSHanoh Haim
1217f7d24e3fSHanoh Haim        s = "digraph trace {\n"
1218f7d24e3fSHanoh Haim
1219f7d24e3fSHanoh Haim        s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"
1220f7d24e3fSHanoh Haim
1221f7d24e3fSHanoh Haim        s += "\n#ASN clustering\n"
1222f7d24e3fSHanoh Haim        for asn in ASNs:
1223f7d24e3fSHanoh Haim            s += '\tsubgraph cluster_%s {\n' % asn
1224f7d24e3fSHanoh Haim            col = backcolorlist.next()
1225f7d24e3fSHanoh Haim            s += '\t\tcolor="#%s%s%s";' % col
1226f7d24e3fSHanoh Haim            s += '\t\tnode [fillcolor="#%s%s%s",style=filled];' % col
1227f7d24e3fSHanoh Haim            s += '\t\tfontsize = 10;'
1228f7d24e3fSHanoh Haim            s += '\t\tlabel = "%s\\n[%s]"\n' % (asn,ASDs[asn])
1229f7d24e3fSHanoh Haim            for ip in ASNs[asn]:
1230f7d24e3fSHanoh Haim
1231f7d24e3fSHanoh Haim                s += '\t\t"%s";\n'%ip
1232f7d24e3fSHanoh Haim            s += "\t}\n"
1233f7d24e3fSHanoh Haim
1234f7d24e3fSHanoh Haim
1235f7d24e3fSHanoh Haim
1236f7d24e3fSHanoh Haim
1237f7d24e3fSHanoh Haim        s += "#endpoints\n"
1238f7d24e3fSHanoh Haim        for p in ports:
1239f7d24e3fSHanoh Haim            s += '\t"%s" [shape=record,color=black,fillcolor=green,style=filled,label="%s|%s"];\n' % (p,p,"|".join(ports[p]))
1240f7d24e3fSHanoh Haim
1241f7d24e3fSHanoh Haim        s += "\n#Blackholes\n"
1242f7d24e3fSHanoh Haim        for bh in blackholes:
1243f7d24e3fSHanoh Haim            s += '\t%s [shape=octagon,color=black,fillcolor=red,style=filled];\n' % bh
1244f7d24e3fSHanoh Haim
1245f7d24e3fSHanoh Haim        if padding:
1246f7d24e3fSHanoh Haim            s += "\n#Padding\n"
1247f7d24e3fSHanoh Haim            pad={}
1248f7d24e3fSHanoh Haim            for snd,rcv in self.res:
1249f7d24e3fSHanoh Haim                if rcv.src not in ports and rcv.haslayer(conf.padding_layer):
1250f7d24e3fSHanoh Haim                    p = rcv.getlayer(conf.padding_layer).load
1251f7d24e3fSHanoh Haim                    if p != "\x00"*len(p):
1252f7d24e3fSHanoh Haim                        pad[rcv.src]=None
1253f7d24e3fSHanoh Haim            for rcv in pad:
1254f7d24e3fSHanoh Haim                s += '\t"%s" [shape=triangle,color=black,fillcolor=red,style=filled];\n' % rcv
1255f7d24e3fSHanoh Haim
1256f7d24e3fSHanoh Haim
1257f7d24e3fSHanoh Haim
1258f7d24e3fSHanoh Haim        s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"
1259f7d24e3fSHanoh Haim
1260f7d24e3fSHanoh Haim
1261f7d24e3fSHanoh Haim        for rtk in rt:
1262f7d24e3fSHanoh Haim            s += "#---[%s\n" % `rtk`
1263f7d24e3fSHanoh Haim            s += '\t\tedge [color="#%s%s%s"];\n' % forecolorlist.next()
1264f7d24e3fSHanoh Haim            trace = rt[rtk]
1265f7d24e3fSHanoh Haim            k = trace.keys()
1266f7d24e3fSHanoh Haim            for n in range(min(k), max(k)):
1267f7d24e3fSHanoh Haim                s += '\t%s ->\n' % trace[n]
1268f7d24e3fSHanoh Haim            s += '\t%s;\n' % trace[max(k)]
1269f7d24e3fSHanoh Haim
1270f7d24e3fSHanoh Haim        s += "}\n";
1271f7d24e3fSHanoh Haim        self.graphdef = s
1272f7d24e3fSHanoh Haim
1273f7d24e3fSHanoh Haim    def graph(self, ASres=None, padding=0, **kargs):
1274f7d24e3fSHanoh Haim        """x.graph(ASres=conf.AS_resolver, other args):
1275f7d24e3fSHanoh Haim        ASres=None          : no AS resolver => no clustering
1276f7d24e3fSHanoh Haim        ASres=AS_resolver() : default whois AS resolver (riswhois.ripe.net)
1277f7d24e3fSHanoh Haim        ASres=AS_resolver_cymru(): use whois.cymru.com whois database
1278f7d24e3fSHanoh Haim        ASres=AS_resolver(server="whois.ra.net")
1279f7d24e3fSHanoh Haim        type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
1280f7d24e3fSHanoh Haim        target: filename or redirect. Defaults pipe to Imagemagick's display program
1281f7d24e3fSHanoh Haim        prog: which graphviz program to use"""
1282f7d24e3fSHanoh Haim        if ASres is None:
1283f7d24e3fSHanoh Haim            ASres = conf.AS_resolver
1284f7d24e3fSHanoh Haim        if (self.graphdef is None or
1285f7d24e3fSHanoh Haim            self.graphASres != ASres or
1286f7d24e3fSHanoh Haim            self.graphpadding != padding):
1287f7d24e3fSHanoh Haim            self.make_graph(ASres,padding)
1288f7d24e3fSHanoh Haim
1289f7d24e3fSHanoh Haim        return do_graph(self.graphdef, **kargs)
1290f7d24e3fSHanoh Haim
1291f7d24e3fSHanoh Haim
1292f7d24e3fSHanoh Haim
1293f7d24e3fSHanoh Haim@conf.commands.register
1294f7d24e3fSHanoh Haimdef traceroute(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, filter=None, timeout=2, verbose=None, **kargs):
1295f7d24e3fSHanoh Haim    """Instant TCP traceroute
1296f7d24e3fSHanoh Haimtraceroute(target, [maxttl=30,] [dport=80,] [sport=80,] [verbose=conf.verb]) -> None
1297f7d24e3fSHanoh Haim"""
1298f7d24e3fSHanoh Haim    if verbose is None:
1299f7d24e3fSHanoh Haim        verbose = conf.verb
1300f7d24e3fSHanoh Haim    if filter is None:
1301f7d24e3fSHanoh Haim        # we only consider ICMP error packets and TCP packets with at
1302f7d24e3fSHanoh Haim        # least the ACK flag set *and* either the SYN or the RST flag
1303f7d24e3fSHanoh Haim        # set
1304f7d24e3fSHanoh Haim        filter="(icmp and (icmp[0]=3 or icmp[0]=4 or icmp[0]=5 or icmp[0]=11 or icmp[0]=12)) or (tcp and (tcp[13] & 0x16 > 0x10))"
1305f7d24e3fSHanoh Haim    if l4 is None:
1306f7d24e3fSHanoh Haim        a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport),
1307f7d24e3fSHanoh Haim                 timeout=timeout, filter=filter, verbose=verbose, **kargs)
1308f7d24e3fSHanoh Haim    else:
1309f7d24e3fSHanoh Haim        # this should always work
1310f7d24e3fSHanoh Haim        filter="ip"
1311f7d24e3fSHanoh Haim        a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4,
1312f7d24e3fSHanoh Haim                 timeout=timeout, filter=filter, verbose=verbose, **kargs)
1313f7d24e3fSHanoh Haim
1314f7d24e3fSHanoh Haim    a = TracerouteResult(a.res)
1315f7d24e3fSHanoh Haim    if verbose:
1316f7d24e3fSHanoh Haim        a.show()
1317f7d24e3fSHanoh Haim    return a,b
1318f7d24e3fSHanoh Haim
1319f7d24e3fSHanoh Haim
1320f7d24e3fSHanoh Haim
1321f7d24e3fSHanoh Haim#############################
1322f7d24e3fSHanoh Haim## Simple TCP client stack ##
1323f7d24e3fSHanoh Haim#############################
1324f7d24e3fSHanoh Haim
1325f7d24e3fSHanoh Haimclass TCP_client(Automaton):
1326f7d24e3fSHanoh Haim
1327f7d24e3fSHanoh Haim    def parse_args(self, ip, port, *args, **kargs):
1328f7d24e3fSHanoh Haim        self.dst = iter(Net(ip)).next()
1329f7d24e3fSHanoh Haim        self.dport = port
1330f7d24e3fSHanoh Haim        self.sport = random.randrange(0,2**16)
1331f7d24e3fSHanoh Haim        self.l4 = IP(dst=ip)/TCP(sport=self.sport, dport=self.dport, flags=0,
1332f7d24e3fSHanoh Haim                                 seq=random.randrange(0,2**32))
1333f7d24e3fSHanoh Haim        self.src = self.l4.src
1334f7d24e3fSHanoh Haim        self.swin=self.l4[TCP].window
1335f7d24e3fSHanoh Haim        self.dwin=1
1336f7d24e3fSHanoh Haim        self.rcvbuf=""
1337f7d24e3fSHanoh Haim        bpf = "host %s  and host %s and port %i and port %i" % (self.src,
1338f7d24e3fSHanoh Haim                                                                self.dst,
1339f7d24e3fSHanoh Haim                                                                self.sport,
1340f7d24e3fSHanoh Haim                                                                self.dport)
1341f7d24e3fSHanoh Haim
1342f7d24e3fSHanoh Haim#        bpf=None
1343f7d24e3fSHanoh Haim        Automaton.parse_args(self, filter=bpf, **kargs)
1344f7d24e3fSHanoh Haim
1345f7d24e3fSHanoh Haim
1346f7d24e3fSHanoh Haim    def master_filter(self, pkt):
1347f7d24e3fSHanoh Haim        return (IP in pkt and
1348f7d24e3fSHanoh Haim                pkt[IP].src == self.dst and
1349f7d24e3fSHanoh Haim                pkt[IP].dst == self.src and
1350f7d24e3fSHanoh Haim                TCP in pkt and
1351f7d24e3fSHanoh Haim                pkt[TCP].sport == self.dport and
1352f7d24e3fSHanoh Haim                pkt[TCP].dport == self.sport and
1353f7d24e3fSHanoh Haim                self.l4[TCP].seq >= pkt[TCP].ack and # XXX: seq/ack 2^32 wrap up
1354f7d24e3fSHanoh Haim                ((self.l4[TCP].ack == 0) or (self.l4[TCP].ack <= pkt[TCP].seq <= self.l4[TCP].ack+self.swin)) )
1355f7d24e3fSHanoh Haim
1356f7d24e3fSHanoh Haim
1357f7d24e3fSHanoh Haim    @ATMT.state(initial=1)
1358f7d24e3fSHanoh Haim    def START(self):
1359f7d24e3fSHanoh Haim        pass
1360f7d24e3fSHanoh Haim
1361f7d24e3fSHanoh Haim    @ATMT.state()
1362f7d24e3fSHanoh Haim    def SYN_SENT(self):
1363f7d24e3fSHanoh Haim        pass
1364f7d24e3fSHanoh Haim
1365f7d24e3fSHanoh Haim    @ATMT.state()
1366f7d24e3fSHanoh Haim    def ESTABLISHED(self):
1367f7d24e3fSHanoh Haim        pass
1368f7d24e3fSHanoh Haim
1369f7d24e3fSHanoh Haim    @ATMT.state()
1370f7d24e3fSHanoh Haim    def LAST_ACK(self):
1371f7d24e3fSHanoh Haim        pass
1372f7d24e3fSHanoh Haim
1373f7d24e3fSHanoh Haim    @ATMT.state(final=1)
1374f7d24e3fSHanoh Haim    def CLOSED(self):
1375f7d24e3fSHanoh Haim        pass
1376f7d24e3fSHanoh Haim
1377f7d24e3fSHanoh Haim
1378f7d24e3fSHanoh Haim    @ATMT.condition(START)
1379f7d24e3fSHanoh Haim    def connect(self):
1380f7d24e3fSHanoh Haim        raise self.SYN_SENT()
1381f7d24e3fSHanoh Haim    @ATMT.action(connect)
1382f7d24e3fSHanoh Haim    def send_syn(self):
1383f7d24e3fSHanoh Haim        self.l4[TCP].flags = "S"
1384f7d24e3fSHanoh Haim        self.send(self.l4)
1385f7d24e3fSHanoh Haim        self.l4[TCP].seq += 1
1386f7d24e3fSHanoh Haim
1387f7d24e3fSHanoh Haim
1388f7d24e3fSHanoh Haim    @ATMT.receive_condition(SYN_SENT)
1389f7d24e3fSHanoh Haim    def synack_received(self, pkt):
1390f7d24e3fSHanoh Haim        if pkt[TCP].flags & 0x3f == 0x12:
1391f7d24e3fSHanoh Haim            raise self.ESTABLISHED().action_parameters(pkt)
1392f7d24e3fSHanoh Haim    @ATMT.action(synack_received)
1393f7d24e3fSHanoh Haim    def send_ack_of_synack(self, pkt):
1394f7d24e3fSHanoh Haim        self.l4[TCP].ack = pkt[TCP].seq+1
1395f7d24e3fSHanoh Haim        self.l4[TCP].flags = "A"
1396f7d24e3fSHanoh Haim        self.send(self.l4)
1397f7d24e3fSHanoh Haim
1398f7d24e3fSHanoh Haim    @ATMT.receive_condition(ESTABLISHED)
1399f7d24e3fSHanoh Haim    def incoming_data_received(self, pkt):
1400f7d24e3fSHanoh Haim        if not isinstance(pkt[TCP].payload, NoPayload) and not isinstance(pkt[TCP].payload, conf.padding_layer):
1401f7d24e3fSHanoh Haim            raise self.ESTABLISHED().action_parameters(pkt)
1402f7d24e3fSHanoh Haim    @ATMT.action(incoming_data_received)
1403f7d24e3fSHanoh Haim    def receive_data(self,pkt):
1404f7d24e3fSHanoh Haim        data = str(pkt[TCP].payload)
1405f7d24e3fSHanoh Haim        if data and self.l4[TCP].ack == pkt[TCP].seq:
1406f7d24e3fSHanoh Haim            self.l4[TCP].ack += len(data)
1407f7d24e3fSHanoh Haim            self.l4[TCP].flags = "A"
1408f7d24e3fSHanoh Haim            self.send(self.l4)
1409f7d24e3fSHanoh Haim            self.rcvbuf += data
1410f7d24e3fSHanoh Haim            if pkt[TCP].flags & 8 != 0: #PUSH
1411f7d24e3fSHanoh Haim                self.oi.tcp.send(self.rcvbuf)
1412f7d24e3fSHanoh Haim                self.rcvbuf = ""
1413f7d24e3fSHanoh Haim
1414f7d24e3fSHanoh Haim    @ATMT.ioevent(ESTABLISHED,name="tcp", as_supersocket="tcplink")
1415f7d24e3fSHanoh Haim    def outgoing_data_received(self, fd):
1416f7d24e3fSHanoh Haim        raise self.ESTABLISHED().action_parameters(fd.recv())
1417f7d24e3fSHanoh Haim    @ATMT.action(outgoing_data_received)
1418f7d24e3fSHanoh Haim    def send_data(self, d):
1419f7d24e3fSHanoh Haim        self.l4[TCP].flags = "PA"
1420f7d24e3fSHanoh Haim        self.send(self.l4/d)
1421f7d24e3fSHanoh Haim        self.l4[TCP].seq += len(d)
1422f7d24e3fSHanoh Haim
1423f7d24e3fSHanoh Haim
1424f7d24e3fSHanoh Haim    @ATMT.receive_condition(ESTABLISHED)
1425f7d24e3fSHanoh Haim    def reset_received(self, pkt):
1426f7d24e3fSHanoh Haim        if pkt[TCP].flags & 4 != 0:
1427f7d24e3fSHanoh Haim            raise self.CLOSED()
1428f7d24e3fSHanoh Haim
1429f7d24e3fSHanoh Haim    @ATMT.receive_condition(ESTABLISHED)
1430f7d24e3fSHanoh Haim    def fin_received(self, pkt):
1431f7d24e3fSHanoh Haim        if pkt[TCP].flags & 0x1 == 1:
1432f7d24e3fSHanoh Haim            raise self.LAST_ACK().action_parameters(pkt)
1433f7d24e3fSHanoh Haim    @ATMT.action(fin_received)
1434f7d24e3fSHanoh Haim    def send_finack(self, pkt):
1435f7d24e3fSHanoh Haim        self.l4[TCP].flags = "FA"
1436f7d24e3fSHanoh Haim        self.l4[TCP].ack = pkt[TCP].seq+1
1437f7d24e3fSHanoh Haim        self.send(self.l4)
1438f7d24e3fSHanoh Haim        self.l4[TCP].seq += 1
1439f7d24e3fSHanoh Haim
1440f7d24e3fSHanoh Haim    @ATMT.receive_condition(LAST_ACK)
1441f7d24e3fSHanoh Haim    def ack_of_fin_received(self, pkt):
1442f7d24e3fSHanoh Haim        if pkt[TCP].flags & 0x3f == 0x10:
1443f7d24e3fSHanoh Haim            raise self.CLOSED()
1444f7d24e3fSHanoh Haim
1445f7d24e3fSHanoh Haim
1446f7d24e3fSHanoh Haim
1447f7d24e3fSHanoh Haim
1448f7d24e3fSHanoh Haim#####################
1449f7d24e3fSHanoh Haim## Reporting stuff ##
1450f7d24e3fSHanoh Haim#####################
1451f7d24e3fSHanoh Haim
1452f7d24e3fSHanoh Haimdef report_ports(target, ports):
1453f7d24e3fSHanoh Haim    """portscan a target and output a LaTeX table
1454f7d24e3fSHanoh Haimreport_ports(target, ports) -> string"""
1455f7d24e3fSHanoh Haim    ans,unans = sr(IP(dst=target)/TCP(dport=ports),timeout=5)
1456f7d24e3fSHanoh Haim    rep = "\\begin{tabular}{|r|l|l|}\n\\hline\n"
1457f7d24e3fSHanoh Haim    for s,r in ans:
1458f7d24e3fSHanoh Haim        if not r.haslayer(ICMP):
1459f7d24e3fSHanoh Haim            if r.payload.flags == 0x12:
1460f7d24e3fSHanoh Haim                rep += r.sprintf("%TCP.sport% & open & SA \\\\\n")
1461f7d24e3fSHanoh Haim    rep += "\\hline\n"
1462f7d24e3fSHanoh Haim    for s,r in ans:
1463f7d24e3fSHanoh Haim        if r.haslayer(ICMP):
1464f7d24e3fSHanoh Haim            rep += r.sprintf("%TCPerror.dport% & closed & ICMP type %ICMP.type%/%ICMP.code% from %IP.src% \\\\\n")
1465f7d24e3fSHanoh Haim        elif r.payload.flags != 0x12:
1466f7d24e3fSHanoh Haim            rep += r.sprintf("%TCP.sport% & closed & TCP %TCP.flags% \\\\\n")
1467f7d24e3fSHanoh Haim    rep += "\\hline\n"
1468f7d24e3fSHanoh Haim    for i in unans:
1469f7d24e3fSHanoh Haim        rep += i.sprintf("%TCP.dport% & ? & unanswered \\\\\n")
1470f7d24e3fSHanoh Haim    rep += "\\hline\n\\end{tabular}\n"
1471f7d24e3fSHanoh Haim    return rep
1472f7d24e3fSHanoh Haim
1473f7d24e3fSHanoh Haim
1474f7d24e3fSHanoh Haim
1475f7d24e3fSHanoh Haimdef IPID_count(lst, funcID=lambda x:x[1].id, funcpres=lambda x:x[1].summary()):
1476f7d24e3fSHanoh Haim    idlst = map(funcID, lst)
1477f7d24e3fSHanoh Haim    idlst.sort()
1478f7d24e3fSHanoh Haim    classes = [idlst[0]]+map(lambda x:x[1],filter(lambda (x,y): abs(x-y)>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:])))
1479f7d24e3fSHanoh Haim    lst = map(lambda x:(funcID(x), funcpres(x)), lst)
1480f7d24e3fSHanoh Haim    lst.sort()
1481f7d24e3fSHanoh Haim    print "Probably %i classes:" % len(classes), classes
1482f7d24e3fSHanoh Haim    for id,pr in lst:
1483f7d24e3fSHanoh Haim        print "%5i" % id, pr
1484f7d24e3fSHanoh Haim
1485f7d24e3fSHanoh Haim
1486f7d24e3fSHanoh Haimdef fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0):
1487f7d24e3fSHanoh Haim    load = "XXXXYYYYYYYYYY"
1488f7d24e3fSHanoh Haim#    getmacbyip(target)
1489f7d24e3fSHanoh Haim#    pkt = IP(dst=target, id=RandShort(), options="\x22"*40)/UDP()/load
1490f7d24e3fSHanoh Haim    pkt = IP(dst=target, id=RandShort(), options="\x00"*40, flags=1)/UDP(sport=sport, dport=sport)/load
1491f7d24e3fSHanoh Haim    s=conf.L3socket()
1492f7d24e3fSHanoh Haim    intr=0
1493f7d24e3fSHanoh Haim    found={}
1494f7d24e3fSHanoh Haim    try:
1495f7d24e3fSHanoh Haim        while 1:
1496f7d24e3fSHanoh Haim            try:
1497f7d24e3fSHanoh Haim                if not intr:
1498f7d24e3fSHanoh Haim                    s.send(pkt)
1499f7d24e3fSHanoh Haim                sin,sout,serr = select([s],[],[],timeout)
1500f7d24e3fSHanoh Haim                if not sin:
1501f7d24e3fSHanoh Haim                    continue
1502f7d24e3fSHanoh Haim                ans=s.recv(1600)
1503f7d24e3fSHanoh Haim                if not isinstance(ans, IP): #TODO: IPv6
1504f7d24e3fSHanoh Haim                    continue
1505f7d24e3fSHanoh Haim                if not isinstance(ans.payload, ICMP):
1506f7d24e3fSHanoh Haim                    continue
1507f7d24e3fSHanoh Haim                if not isinstance(ans.payload.payload, IPerror):
1508f7d24e3fSHanoh Haim                    continue
1509f7d24e3fSHanoh Haim                if ans.payload.payload.dst != target:
1510f7d24e3fSHanoh Haim                    continue
1511f7d24e3fSHanoh Haim                if ans.src  != target:
1512f7d24e3fSHanoh Haim                    print "leak from", ans.src,
1513f7d24e3fSHanoh Haim
1514f7d24e3fSHanoh Haim
1515f7d24e3fSHanoh Haim#                print repr(ans)
1516f7d24e3fSHanoh Haim                if not ans.haslayer(conf.padding_layer):
1517f7d24e3fSHanoh Haim                    continue
1518f7d24e3fSHanoh Haim
1519f7d24e3fSHanoh Haim
1520f7d24e3fSHanoh Haim#                print repr(ans.payload.payload.payload.payload)
1521f7d24e3fSHanoh Haim
1522f7d24e3fSHanoh Haim#                if not isinstance(ans.payload.payload.payload.payload, conf.raw_layer):
1523f7d24e3fSHanoh Haim#                    continue
1524f7d24e3fSHanoh Haim#                leak = ans.payload.payload.payload.payload.load[len(load):]
1525f7d24e3fSHanoh Haim                leak = ans.getlayer(conf.padding_layer).load
1526f7d24e3fSHanoh Haim                if leak not in found:
1527f7d24e3fSHanoh Haim                    found[leak]=None
1528f7d24e3fSHanoh Haim                    linehexdump(leak, onlyasc=onlyasc)
1529f7d24e3fSHanoh Haim            except KeyboardInterrupt:
1530f7d24e3fSHanoh Haim                if intr:
1531f7d24e3fSHanoh Haim                    raise
1532f7d24e3fSHanoh Haim                intr=1
1533f7d24e3fSHanoh Haim    except KeyboardInterrupt:
1534f7d24e3fSHanoh Haim        pass
1535f7d24e3fSHanoh Haim
1536f7d24e3fSHanoh Haimdef fragleak2(target, timeout=0.4, onlyasc=0):
1537f7d24e3fSHanoh Haim    found={}
1538f7d24e3fSHanoh Haim    try:
1539f7d24e3fSHanoh Haim        while 1:
1540f7d24e3fSHanoh Haim            p = sr1(IP(dst=target, options="\x00"*40, proto=200)/"XXXXYYYYYYYYYYYY",timeout=timeout,verbose=0)
1541f7d24e3fSHanoh Haim            if not p:
1542f7d24e3fSHanoh Haim                continue
1543f7d24e3fSHanoh Haim            if conf.padding_layer in p:
1544f7d24e3fSHanoh Haim                leak  = p[conf.padding_layer].load
1545f7d24e3fSHanoh Haim                if leak not in found:
1546f7d24e3fSHanoh Haim                    found[leak]=None
1547f7d24e3fSHanoh Haim                    linehexdump(leak,onlyasc=onlyasc)
1548f7d24e3fSHanoh Haim    except:
1549f7d24e3fSHanoh Haim        pass
1550f7d24e3fSHanoh Haim
1551f7d24e3fSHanoh Haim
1552f7d24e3fSHanoh Haimconf.stats_classic_protocols += [TCP,UDP,ICMP]
1553f7d24e3fSHanoh Haimconf.stats_dot11_protocols += [TCP,UDP,ICMP]
1554f7d24e3fSHanoh Haim
1555f7d24e3fSHanoh Haimif conf.ipv6_enabled:
1556f7d24e3fSHanoh Haim    import scapy.layers.inet6
1557