root/pm/trunk/deps/scapy-patches/dns.patch
@
5525
| Revision 5525, 12.2 kB (checked in by nopper, 7 months ago) |
|---|
-
scapy/layers/dns.py
diff -r 7a211173d33f scapy/layers/dns.py
a b 10 10 from scapy.ansmachine import * 11 11 from scapy.layers.inet import UDP 12 12 13 def 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 19 def 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 13 27 class DNSStrField(StrField): 14 28 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) 21 30 def getfield(self, pkt, s): 22 31 n = "" 23 32 while 1: … … 45 54 x = x.payload 46 55 i += 1 47 56 return i 48 57 49 58 def i2m(self, pkt, x): 50 59 if x is None: 51 60 x = self._countRR(pkt) … … 54 63 if x is None: 55 64 x = self._countRR(pkt) 56 65 return x 57 58 66 59 def DNSgetstr(s,p): 67 68 def DNSgetstr(s,p,off=12): 60 69 name = "" 70 rawname = "" 71 compressed = False 61 72 q = 0 62 73 jpath = [p] 63 74 while 1: … … 67 78 l = ord(s[p]) 68 79 p += 1 69 80 if l & 0xc0: 81 if not compressed: 82 rawname += s[p-1] + s[p] 83 compressed = True 70 84 if not q: 71 85 q = p+1 72 86 if p >= len(s): 73 87 warning("DNS incomplete jump token at (ofs=%i)" % p) 74 88 break 75 p = ((l & 0x3f) << 8) + ord(s[p]) - 1289 p = ((l & 0x3f) << 8) + ord(s[p]) - off 76 90 if p in jpath: 77 91 warning("DNS decompression loop detected") 78 92 break 79 93 jpath.append(p) 80 94 continue 81 95 elif l > 0: 96 if not compressed: 97 rawname += s[p-1] + s[p:p+l] 82 98 name += s[p:p+l]+"." 83 99 p += l 84 100 continue 85 101 break 86 102 if q: 87 103 p = q 88 return name,p 89 104 return name,p,compressed and rawname or "" 105 90 106 91 107 class DNSRRField(StrField): 92 108 holds_packets=1 … … 98 114 if x is None: 99 115 return "" 100 116 return str(x) 101 def decodeRR(self, name, s, p): 117 118 def decodeRR(self, name, origname, s, p): 102 119 ret = s[p:p+10] 103 120 type,cls,ttl,rdlen = struct.unpack("!HHIH", ret) 104 121 p += 10 105 122 rr = DNSRR("\x00"+ret+s[p:p+rdlen]) 106 123 if rr.type in [2, 3, 4, 5]: 107 rr.rdata = DNSgetstr(s,p)[0]124 rr.rdata,_,rr.origrdata = DNSgetstr(s,p) 108 125 del(rr.rdlen) 109 126 110 127 p += rdlen 111 128 112 129 rr.rrname = name 130 rr.origrrname = origname 113 131 return rr,p 114 132 def getfield(self, pkt, s): 115 133 if type(s) is tuple : … … 123 141 return s,"" 124 142 while c: 125 143 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) 128 146 if ret is None: 129 147 ret = rr 130 148 else: 131 149 ret.add_payload(rr) 150 132 151 if self.passon: 133 152 return (s,p),ret 134 153 else: 135 154 return s[p:],ret 136 137 155 156 138 157 class DNSQRField(DNSRRField): 139 158 holds_packets=1 140 def decodeRR(self, name, s, p):159 def decodeRR(self, name, origname, s, p): 141 160 ret = s[p:p+4] 142 161 p += 4 143 162 rr = DNSQR("\x00"+ret) 144 163 rr.qname = name 145 164 return rr,p 146 147 165 148 166 149 167 class RDataField(StrLenField): 150 168 def m2i(self, pkt, s): … … 155 173 family = socket.AF_INET6 156 174 elif pkt.type == 12: 157 175 s = DNSgetstr(s, 0)[0] 158 if family is not None: 176 if family is not None: 159 177 s = inet_ntop(family, s) 160 178 return s 161 179 def i2m(self, pkt, s): … … 165 183 elif pkt.type == 28: 166 184 if s: 167 185 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) 172 188 return s 173 189 190 174 191 class RDLenField(Field): 175 192 def __init__(self, name): 176 193 Field.__init__(self, name, None, "H") 177 194 def i2m(self, pkt, x): 178 195 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 181 203 return x 182 204 def i2h(self, pkt, x): 183 205 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 186 213 return x 187 214 188 215 189 216 class DNS(Packet): 190 217 name = "DNS" … … 210 237 and self.id == other.id 211 238 and self.qr == 1 212 239 and other.qr == 0) 213 240 214 241 def mysummary(self): 215 242 type = ["Qry","Ans"][self.qr] 216 243 name = "" … … 224 251 name = ' "%s"' % self.qd.qname 225 252 return 'DNS %s%s ' % (type, name) 226 253 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 227 378 dnstypes = { 0:"ANY", 255:"ALL", 228 379 1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", 229 380 9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", 230 381 17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"} 231 382 383 232 384 dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"} 233 385 dnsqtypes.update(dnstypes) 234 386 dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'} 235 387 236 388 389 class OriginalDataField(StrField): 390 def i2m(self, pkt, x): 391 return '' 392 237 393 class DNSQR(Packet): 238 394 name = "DNS Question Record" 239 395 show_indent=0 240 396 fields_desc = [ DNSStrField("qname",""), 241 397 ShortEnumField("qtype", 1, dnsqtypes), 242 398 ShortEnumField("qclass", 1, dnsclasses) ] 243 244 399 245 400 246 401 class DNSRR(Packet): 247 402 name = "DNS Resource Record" … … 251 406 ShortEnumField("rclass", 1, dnsclasses), 252 407 IntField("ttl", 0), 253 408 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", "")] 255 412 256 413 bind_layers( UDP, DNS, dport=53) 257 414 bind_layers( UDP, DNS, sport=53) … … 275 432 return r.getlayer(DNS).rcode 276 433 else: 277 434 return -1 278 279 280 435 281 436 282 437 @conf.commands.register 283 438 def dyndns_del(nameserver, name, type="ALL", ttl=10): … … 297 452 return r.getlayer(DNS).rcode 298 453 else: 299 454 return -1 300 455 301 456 302 457 class DNS_am(AnsweringMachine): 303 458 function_name="dns_spoof" … … 312 467 313 468 def is_request(self, req): 314 469 return req.haslayer(DNS) and req.getlayer(DNS).qr == 0 315 470 316 471 def make_reply(self, req): 317 472 ip = req.getlayer(IP) 318 473 dns = req.getlayer(DNS) … … 322 477 an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata)) 323 478 return resp 324 479 325
Note: See TracBrowser
for help on using the browser.
