root/pm/trunk/deps/scapy-patches/dns.patch @ 5525

Revision 5525, 12.2 kB (checked in by nopper, 7 months ago)

Refreshing scapy patches

  • scapy/layers/dns.py

    diff -r 7a211173d33f scapy/layers/dns.py
    a b  
    1010from scapy.ansmachine import * 
    1111from scapy.layers.inet import UDP 
    1212 
     13def unroll(rrname): 
     14    ret = [] 
     15    splitted = rrname.split('.') 
     16    for i in xrange(len(splitted) - 1): 
     17        yield '.'.join(splitted[0:i]), '.'.join(splitted[i:]) 
     18 
     19def convert(x): 
     20    x = [k[:63] for k in x.split(".")] # Truncate chunks that cannont be encoded (more than 63 bytes..) 
     21    x = map(lambda y: chr(len(y))+y, x) 
     22    x = "".join(x) 
     23    if x[-1] != "\x00": 
     24        x += "\x00" 
     25    return x 
     26 
    1327class DNSStrField(StrField): 
    1428    def i2m(self, pkt, x): 
    15         x = [k[:63] for k in x.split(".")] # Truncate chunks that cannont be encoded (more than 63 bytes..) 
    16         x = map(lambda y: chr(len(y))+y, x) 
    17         x = "".join(x) 
    18         if x[-1] != "\x00": 
    19             x += "\x00" 
    20         return x 
     29        return convert(x) 
    2130    def getfield(self, pkt, s): 
    2231        n = "" 
    2332        while 1: 
     
    4554            x = x.payload 
    4655            i += 1 
    4756        return i 
    48          
     57 
    4958    def i2m(self, pkt, x): 
    5059        if x is None: 
    5160            x = self._countRR(pkt) 
     
    5463        if x is None: 
    5564            x = self._countRR(pkt) 
    5665        return x 
    57      
    5866 
    59 def DNSgetstr(s,p): 
     67 
     68def DNSgetstr(s,p,off=12): 
    6069    name = "" 
     70    rawname = "" 
     71    compressed = False 
    6172    q = 0 
    6273    jpath = [p] 
    6374    while 1: 
     
    6778        l = ord(s[p]) 
    6879        p += 1 
    6980        if l & 0xc0: 
     81            if not compressed: 
     82                rawname += s[p-1] + s[p] 
     83            compressed = True 
    7084            if not q: 
    7185                q = p+1 
    7286            if p >= len(s): 
    7387                warning("DNS incomplete jump token at (ofs=%i)" % p) 
    7488                break 
    75             p = ((l & 0x3f) << 8) + ord(s[p]) - 12 
     89            p = ((l & 0x3f) << 8) + ord(s[p]) - off 
    7690            if p in jpath: 
    7791                warning("DNS decompression loop detected") 
    7892                break 
    7993            jpath.append(p) 
    8094            continue 
    8195        elif l > 0: 
     96            if not compressed: 
     97                rawname += s[p-1] + s[p:p+l] 
    8298            name += s[p:p+l]+"." 
    8399            p += l 
    84100            continue 
    85101        break 
    86102    if q: 
    87103        p = q 
    88     return name,p 
    89          
     104    return name,p,compressed and rawname or "" 
     105 
    90106 
    91107class DNSRRField(StrField): 
    92108    holds_packets=1 
     
    98114        if x is None: 
    99115            return "" 
    100116        return str(x) 
    101     def decodeRR(self, name, s, p): 
     117 
     118    def decodeRR(self, name, origname, s, p): 
    102119        ret = s[p:p+10] 
    103120        type,cls,ttl,rdlen = struct.unpack("!HHIH", ret) 
    104121        p += 10 
    105122        rr = DNSRR("\x00"+ret+s[p:p+rdlen]) 
    106123        if rr.type in [2, 3, 4, 5]: 
    107             rr.rdata = DNSgetstr(s,p)[0] 
     124            rr.rdata,_,rr.origrdata = DNSgetstr(s,p) 
    108125        del(rr.rdlen) 
    109          
     126 
    110127        p += rdlen 
    111          
     128 
    112129        rr.rrname = name 
     130        rr.origrrname = origname 
    113131        return rr,p 
    114132    def getfield(self, pkt, s): 
    115133        if type(s) is tuple : 
     
    123141            return s,"" 
    124142        while c: 
    125143            c -= 1 
    126             name,p = DNSgetstr(s,p) 
    127             rr,p = self.decodeRR(name, s, p) 
     144            name,p,origname = DNSgetstr(s,p) 
     145            rr,p = self.decodeRR(name, origname, s, p) 
    128146            if ret is None: 
    129147                ret = rr 
    130148            else: 
    131149                ret.add_payload(rr) 
     150 
    132151        if self.passon: 
    133152            return (s,p),ret 
    134153        else: 
    135154            return s[p:],ret 
    136              
    137              
     155 
     156 
    138157class DNSQRField(DNSRRField): 
    139158    holds_packets=1 
    140     def decodeRR(self, name, s, p): 
     159    def decodeRR(self, name, origname, s, p): 
    141160        ret = s[p:p+4] 
    142161        p += 4 
    143162        rr = DNSQR("\x00"+ret) 
    144163        rr.qname = name 
    145164        return rr,p 
    146          
    147          
     165 
    148166 
    149167class RDataField(StrLenField): 
    150168    def m2i(self, pkt, s): 
     
    155173            family = socket.AF_INET6 
    156174        elif pkt.type == 12: 
    157175            s = DNSgetstr(s, 0)[0] 
    158         if family is not None:     
     176        if family is not None: 
    159177            s = inet_ntop(family, s) 
    160178        return s 
    161179    def i2m(self, pkt, s): 
     
    165183        elif pkt.type == 28: 
    166184            if s: 
    167185                s = inet_pton(socket.AF_INET6, s) 
    168         elif pkt.type in [2,3,4,5]: 
    169             s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) 
    170             if ord(s[-1]): 
    171                 s += "\x00" 
     186        elif pkt.type in [2,3,4,5,12]: 
     187            s = convert(s) 
    172188        return s 
    173189 
     190 
    174191class RDLenField(Field): 
    175192    def __init__(self, name): 
    176193        Field.__init__(self, name, None, "H") 
    177194    def i2m(self, pkt, x): 
    178195        if x is None: 
    179             rdataf = pkt.get_field("rdata") 
    180             x = len(rdataf.i2m(pkt, pkt.rdata)) 
     196            val = pkt.getfieldval('origrdata') 
     197            x = len(val) 
     198 
     199            if x == 0: 
     200                rdataf = pkt.get_field("rdata") 
     201                x = len(rdataf.i2m(pkt, pkt.rdata)) 
     202 
    181203        return x 
    182204    def i2h(self, pkt, x): 
    183205        if x is None: 
    184             rdataf = pkt.get_field("rdata") 
    185             x = len(rdataf.i2m(pkt, pkt.rdata)) 
     206            val = pkt.getfieldval('origrdata') 
     207            x = len(val) 
     208 
     209            if x == 0: 
     210                rdataf = pkt.get_field("rdata") 
     211                x = len(rdataf.i2m(pkt, pkt.rdata)) 
     212 
    186213        return x 
    187      
     214 
    188215 
    189216class DNS(Packet): 
    190217    name = "DNS" 
     
    210237                and self.id == other.id 
    211238                and self.qr == 1 
    212239                and other.qr == 0) 
    213          
     240 
    214241    def mysummary(self): 
    215242        type = ["Qry","Ans"][self.qr] 
    216243        name = "" 
     
    224251                name = ' "%s"' % self.qd.qname 
    225252        return 'DNS %s%s ' % (type, name) 
    226253 
     254    def do_build(self): 
     255        pay="" 
     256        cnames = {} 
     257 
     258        def addpointer(x, pos): 
     259            if x in cnames: 
     260                return 
     261 
     262            if x and x[-1] == '.': 
     263                x = x[:-1] 
     264 
     265            for f, d in unroll(x): 
     266                if d not in cnames: 
     267                    cnames[d] = pos + x.find(d) 
     268 
     269        def getpointer(x): 
     270            if x[-1] == '.': 
     271                x = x[:-1] 
     272            if x in cnames: 
     273                return cnames[x] 
     274            return -1 
     275 
     276        for f in self.fields_desc[:13]: 
     277            val = self.getfieldval(f.name) 
     278            if isinstance(val, RawVal): 
     279                pay += str(val) 
     280            else: 
     281                pay = f.addfield(self, pay, val) 
     282 
     283        for f in self.fields_desc[13:]: 
     284            try: 
     285                val = self.fields[f.name] 
     286            except KeyError: 
     287                continue 
     288 
     289            if not val: 
     290                continue 
     291 
     292            while not isinstance(val, NoPayload): 
     293                if isinstance(val, DNSQR): 
     294                    addpointer(val.getfieldval('qname'), len(pay)) 
     295                    pay += str(val) 
     296                elif isinstance(val, DNSRR): 
     297                    oldpos = len(pay) 
     298 
     299                    rrname  = val.getfieldval('rrname') 
     300                    orrname = val.getfieldval('origrrname') 
     301                    drrname = orrname and \ 
     302                        DNSgetstr(pay + orrname, len(pay), 0)[0] or None 
     303 
     304                    if drrname == rrname: 
     305                        pay += orrname 
     306                    else: 
     307                        compressed = False 
     308 
     309                        for first, domain in unroll(rrname): 
     310                            idx = getpointer(domain) 
     311 
     312                            if idx >= 0: 
     313                                pay += first and convert(first)[:-1] or '' 
     314                                pay += struct.pack("!H", 0xc000 | idx) 
     315                                compressed = True 
     316                                break 
     317 
     318                        if not compressed: 
     319                            pay = val.fields_desc[0].addfield(val, pay, rrname) 
     320 
     321                    addpointer(rrname, len(pay) - 1) 
     322                    oldpos = len(pay) 
     323 
     324                    interesting = False 
     325                    rdata = val.getfieldval('rdata') 
     326 
     327                    # First we try to compress the rdata and set origrdata field 
     328                    if val.getfieldval('type') in [2,3,4,5,12]: 
     329                        interesting = True 
     330 
     331                        packrdata = convert(rdata) 
     332                        ordata = val.getfieldval('origrdata') 
     333                        tmppay = pay + "\x00" * 10 
     334 
     335                        drdata = ordata and \ 
     336                            DNSgetstr(tmppay + orrname, len(tmppay), 0)[0] or None 
     337 
     338                        if drdata == rdata: 
     339                            packrdata = ordata 
     340                            val.setfieldval('origrdata', packrdata) 
     341                        else: 
     342                            compressed = False 
     343 
     344                            for first, domain in unroll(rdata): 
     345                                idx = getpointer(domain) 
     346 
     347                                if idx >= 0: 
     348                                    packrdata = first and convert(first)[:-1] or '' 
     349                                    packrdata += struct.pack("!H", 0xc000 | idx) 
     350                                    val.setfieldval('origrdata', packrdata) 
     351                                    compressed = True 
     352                                    break 
     353 
     354                            if not compressed: 
     355                                val.setfieldval('origrdata', packrdata) 
     356 
     357                        addpointer(rdata, oldpos + 10) 
     358                    else: 
     359                        val.setfieldval('origrdata', '') 
     360 
     361                    # These fields could not be compressed 
     362                    for rrf in val.fields_desc[1:5]: 
     363                        rrval = val.getfieldval(rrf.name) 
     364 
     365                        if isinstance(rrval, RawVal): 
     366                            pay += str(rrval) 
     367                        else: 
     368                            pay = rrf.addfield(val, pay, rrval) 
     369 
     370                    if not interesting: 
     371                        pay = val.fields_desc[5].addfield(val, pay, val.getfieldval('rdata')) 
     372                    else: 
     373                        pay += packrdata 
     374 
     375                val = val.payload 
     376        return pay 
     377 
    227378dnstypes = { 0:"ANY", 255:"ALL", 
    228379             1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", 
    229380             9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", 
    230381             17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"} 
    231382 
     383 
    232384dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"} 
    233385dnsqtypes.update(dnstypes) 
    234386dnsclasses =  {1: 'IN',  2: 'CS',  3: 'CH',  4: 'HS',  255: 'ANY'} 
    235387 
    236388 
     389class OriginalDataField(StrField): 
     390    def i2m(self, pkt, x): 
     391        return '' 
     392 
    237393class DNSQR(Packet): 
    238394    name = "DNS Question Record" 
    239395    show_indent=0 
    240396    fields_desc = [ DNSStrField("qname",""), 
    241397                    ShortEnumField("qtype", 1, dnsqtypes), 
    242398                    ShortEnumField("qclass", 1, dnsclasses) ] 
    243                      
    244                      
     399 
    245400 
    246401class DNSRR(Packet): 
    247402    name = "DNS Resource Record" 
     
    251406                    ShortEnumField("rclass", 1, dnsclasses), 
    252407                    IntField("ttl", 0), 
    253408                    RDLenField("rdlen"), 
    254                     RDataField("rdata", "", length_from=lambda pkt:pkt.rdlen) ] 
     409                    RDataField("rdata", "", length_from=lambda pkt:pkt.rdlen), 
     410                    OriginalDataField("origrdata", ""), 
     411                    OriginalDataField("origrrname", "")] 
    255412 
    256413bind_layers( UDP,           DNS,           dport=53) 
    257414bind_layers( UDP,           DNS,           sport=53) 
     
    275432        return r.getlayer(DNS).rcode 
    276433    else: 
    277434        return -1 
    278      
    279      
    280      
     435 
    281436 
    282437@conf.commands.register 
    283438def dyndns_del(nameserver, name, type="ALL", ttl=10): 
     
    297452        return r.getlayer(DNS).rcode 
    298453    else: 
    299454        return -1 
    300      
     455 
    301456 
    302457class DNS_am(AnsweringMachine): 
    303458    function_name="dns_spoof" 
     
    312467 
    313468    def is_request(self, req): 
    314469        return req.haslayer(DNS) and req.getlayer(DNS).qr == 0 
    315      
     470 
    316471    def make_reply(self, req): 
    317472        ip = req.getlayer(IP) 
    318473        dns = req.getlayer(DNS) 
     
    322477                    an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata)) 
    323478        return resp 
    324479 
    325  
Note: See TracBrowser for help on using the browser.