Special StrLenField that handles DNS TEXT data (16)
| 382 | |
| 383 | |
| 384 | class DNSTextField(StrLenField): |
| 385 | """ |
| 386 | Special StrLenField that handles DNS TEXT data (16) |
| 387 | """ |
| 388 | |
| 389 | islist = 1 |
| 390 | |
| 391 | def i2h(self, pkt, x): |
| 392 | if not x: |
| 393 | return [] |
| 394 | return x |
| 395 | |
| 396 | def m2i(self, pkt, s): |
| 397 | ret_s = list() |
| 398 | tmp_s = s |
| 399 | # RDATA contains a list of strings, each are prepended with |
| 400 | # a byte containing the size of the following string. |
| 401 | while tmp_s: |
| 402 | tmp_len = tmp_s[0] + 1 |
| 403 | if tmp_len > len(tmp_s): |
| 404 | log_runtime.info( |
| 405 | "DNS RR TXT prematured end of character-string " |
| 406 | "(size=%i, remaining bytes=%i)", tmp_len, len(tmp_s) |
| 407 | ) |
| 408 | ret_s.append(tmp_s[1:tmp_len]) |
| 409 | tmp_s = tmp_s[tmp_len:] |
| 410 | return ret_s |
| 411 | |
| 412 | def any2i(self, pkt, x): |
| 413 | if isinstance(x, (str, bytes)): |
| 414 | return [x] |
| 415 | return x |
| 416 | |
| 417 | def i2len(self, pkt, x): |
| 418 | return len(self.i2m(pkt, x)) |
| 419 | |
| 420 | def i2m(self, pkt, s): |
| 421 | ret_s = b"" |
| 422 | for text in s: |
| 423 | if not text: |
| 424 | ret_s += b"\x00" |
| 425 | continue |
| 426 | text = bytes_encode(text) |
| 427 | # The initial string must be split into a list of strings |
| 428 | # prepended with theirs sizes. |
| 429 | while len(text) >= 255: |
| 430 | ret_s += b"\xff" + text[:255] |
| 431 | text = text[255:] |
| 432 | # The remaining string is less than 255 bytes long |
| 433 | if len(text): |
| 434 | ret_s += struct.pack("!B", len(text)) + text |
| 435 | return ret_s |
| 436 | |
| 437 | |
| 438 | # RFC 2671 - Extension Mechanisms for DNS (EDNS0) |