|
| 1 | +[module] |
| 2 | +name = "nptenumalias" |
| 3 | +type = "feature" |
| 4 | +info = "NAPTR ENUM random N aliases" |
| 5 | +desc = "Respond with N number of NAPTR ENUM records containing random E.164 phone numbers (aliases) in SIP service URI. BEWARE: This could result in multiplication." |
| 6 | +author = "ivan.jedek@oryxlabs.com" |
| 7 | +category = "Aliases, loops and chains" |
| 8 | + |
| 9 | +code = ''' |
| 10 | + elif req.first_subdomain == "1" and req.full_domain.endswith(".e164.arpa"): |
| 11 | + # Requesting to translate an E.164 telephone number ending with the digit 1 (e.g., a NAPTR |
| 12 | + # record for 1.<anything>.e164.arpa in reverse). The response will be a SIP service URI |
| 13 | + # pointing to another random E.164 telephone number also ending with the digit 1 (leading |
| 14 | + # here again, producing another alias). While NAPTR ENUM records do not contain aliases |
| 15 | + # like CNAME records, this could achieve similar results by prompting the client to |
| 16 | + # perform consecutive queries to resolve it. |
| 17 | + # BEWARE: This could result in multiplication |
| 18 | +
|
| 19 | + answers = int(req.subdomains[1]) if req.subdomains[1].isnumeric() else 1 |
| 20 | +
|
| 21 | + # figure out the ending part of the domain which is not a number any more |
| 22 | + # in order to preserve the parameters if any |
| 23 | + for i, part in enumerate(req.subdomains): |
| 24 | + if not part.isnumeric(): |
| 25 | + dom_end = '.' + '.'.join(req.subdomains[i:]) |
| 26 | + break |
| 27 | + else: |
| 28 | + dom_end = req.full_domain |
| 29 | +
|
| 30 | + ### DNS header ######## |
| 31 | + buffer = prep_dns_header(b'\x84\x00', req.QURR, answers, 0, 0) |
| 32 | + ### QUESTION SECTION ######## |
| 33 | + if resp.noq: buffer += convDom2Bin(req.full_domain) + req.type_bin + req.class_bin |
| 34 | + ### ANSWER SECTION ######## |
| 35 | + doms = [] |
| 36 | + for i in range(answers): |
| 37 | + random_number = random.getrandbits(30) % 1000000000 |
| 38 | + new_dom = '1.' + str(answers) + '.' + '.'.join(str(random_number)) + dom_end |
| 39 | + order = 0 |
| 40 | + pref = 0 |
| 41 | + flags = b'U' # Flags = "U" (URI) |
| 42 | + service = b'E2U+sip' # Service = SIP |
| 43 | + regex = bytes("!^.*$!" + new_dom + "!", "utf-8") |
| 44 | + replacement = b'\x00' |
| 45 | +
|
| 46 | + data_len = 2+2+1+len(flags)+1+len(service)+1+len(regex)+len(replacement) |
| 47 | + buffer += b'\xc0\x0c' if resp.compress else convDom2Bin(req.full_domain) ## Name |
| 48 | + buffer += getTypeBin("NAPTR") + getClassBin("IN") |
| 49 | + buffer += struct.pack(">L", resp.TTL) ## TTL |
| 50 | + buffer += struct.pack(">H", data_len) ## Data length (2B) |
| 51 | + buffer += struct.pack(">H", order) ## Order (2B) |
| 52 | + buffer += struct.pack(">H", pref) ## Preference (2B) |
| 53 | + buffer += struct.pack(">B", len(flags)) ## Flags Length (1B) |
| 54 | + buffer += flags ## Flags |
| 55 | + buffer += struct.pack(">B", len(service)) ## Service Length (1B) |
| 56 | + buffer += service ## Service |
| 57 | + buffer += struct.pack(">B", len(regex)) ## Regex Length (1B) |
| 58 | + buffer += regex ## Regex |
| 59 | + buffer += replacement ## Replacement |
| 60 | + doms.append(new_dom) |
| 61 | + # log and send |
| 62 | + log("%d NAPTR ENUM aliases: %s" % (answers, ', '.join(map(str, doms[:3])) + (', ...' if answers > 3 else ''))) |
| 63 | + send_buf(self, buffer) |
| 64 | + ##################################################################### |
| 65 | +''' |
0 commit comments