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