def CheckForClientSubnetOption(addr, args, option_code=ASSIGNED_OPTION_CODE): print("Testing for edns-clientsubnet using option code", hex(option_code), file=sys.stderr) cso = ClientSubnetOption(args.subnet, args.mask, option=option_code) message = dns.message.make_query(args.rr, args.type) # Tested authoritative servers seem to use the last code in cases # where they support both. We make the official code last to allow # us to check for support of both draft and official message.use_edns(options=[cso]) if args.recursive: message.flags = message.flags | dns.flags.RD try: r = dns.query.udp(message, addr, timeout=args.timeout) if r.flags & dns.flags.TC: r = dns.query.tcp(message, addr, timeout=args.timeout) except dns.exception.Timeout: print("Timeout: No answer received from %s\n" % args.nameserver, file=sys.stderr) return error = False found = False for options in r.options: # Have not run into anyone who passes back both codes yet # but just in case, we want to check all possible options if isinstance(options, ClientSubnetOption): found = True print("Found ClientSubnetOption...", end=None, file=sys.stderr) if not cso.family == options.family: error = True print("\nFailed: returned family (%d) is different from the passed family (%d)" % (options.family, cso.family), file=sys.stderr) if not cso.calculate_ip() == options.calculate_ip(): error = True print("\nFailed: returned ip (%s) is different from the passed ip (%s)." % (options.calculate_ip(), cso.calculate_ip()), file=sys.stderr) if not options.mask == cso.mask: error = True print("\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)" % (options.mask, cso.mask), file=sys.stderr) if not options.scope != 0: print("\nWarning: scope indicates edns-clientsubnet data is not used", file=sys.stderr) if options.is_draft(): print("\nWarning: detected support for edns-clientsubnet draft code", file=sys.stderr) if found and not error: print("Success", file=sys.stderr) elif found: print("Failed: See error messages above", file=sys.stderr) else: print("Failed: No ClientSubnetOption returned", file=sys.stderr)
def CheckForClientSubnetOption(addr, args, option_code=ASSIGNED_OPTION_CODE): print("Testing for edns-clientsubnet using option code", hex(option_code), file=sys.stderr) cso = ClientSubnetOption(args.subnet, args.mask, option=option_code) message = dns.message.make_query(args.rr, args.type) # Tested authoritative servers seem to use the last code in cases # where they support both. We make the official code last to allow # us to check for support of both draft and official message.use_edns(options=[cso]) try: r = dns.query.udp(message, addr, timeout=args.timeout) if r.flags & dns.flags.TC: r = dns.query.tcp(message, addr, timeout=args.timeout) except dns.exception.Timeout: print("Timeout: No answer received from %s\n" % args.nameserver, file=sys.stderr) sys.exit(3) error = False found = False for options in r.options: # Have not run into anyone who passes back both codes yet # but just in case, we want to check all possible options if isinstance(options, ClientSubnetOption): found = True print("Found ClientSubnetOption...", end=None, file=sys.stderr) if not cso.family == options.family: error = True print("\nFailed: returned family (%d) is different from the passed family (%d)" % (options.family, cso.family), file=sys.stderr) if not cso.calculate_ip() == options.calculate_ip(): error = True print("\nFailed: returned ip (%s) is different from the passed ip (%s)." % (options.calculate_ip(), cso.calculate_ip()), file=sys.stderr) if not options.mask == cso.mask: error = True print("\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)" % (options.mask, cso.mask), file=sys.stderr) if not options.scope != 0: print("\nWarning: scope indicates edns-clientsubnet data is not used", file=sys.stderr) if options.is_draft(): print("\nWarning: detected support for edns-clientsubnet draft code", file=sys.stderr) if found and not error: print("Success", file=sys.stderr) elif found: print("Failed: See error messages above", file=sys.stderr) else: print("Failed: No ClientSubnetOption returned", file=sys.stderr)
else: print "'%s' doesn't look like an IP to me..." % sys.argv[3] sys.exit(1) else: family = 1 ip = 0xC0000200 if len(sys.argv) == 5: mask = int(sys.argv[4]) else: if family == 2: mask = 48 else: mask = 24 addr = socket.gethostbyname(sys.argv[1]) cso = ClientSubnetOption(family, ip, mask) message = dns.message.make_query(sys.argv[2], "A") message.use_edns(options=[cso]) r = dns.query.udp(message, addr) if r.flags & dns.flags.TC: r = dns.query.tcp(message, addr) for options in r.options: if isinstance(options, ClientSubnetOption): assert cso.family == options.family, "returned family (%d) is different from the passed family (%d)" % (options.family, cso.family) assert cso.calculate_ip() == options.calculate_ip(), "returned ip (%s) is different from then passed ip(%s)." % (options.calculate_ip(), cso.calculate_ip()) assert options.mask == cso.mask, "returned mask bits (%d) is different from the passed mask bits (%d)" % (options.mask, cso.mask) assert options.scope != 0, "scope indicates edns-clientsubnet data is not used" print "Success!"
def do_edns_c_query(resolver,ip,family,mask,query, timeout=1.0): # ip - client_ip to fake # family - IP-family (int) # mask - mask to send (int) # query - name to query dns.edns._type_to_class[0x0008] = ClientSubnetOption #client_ip_str=socket.inet_ntoa(struct.pack('!L',ip)) #lprefix = "%s %s %s %d -" % (resolver,query,client_ip_str,mask) lprefix=ip cso = ClientSubnetOption(family, ip, mask) message = dns.message.make_query(query, "A") message.use_edns(options=[cso]) # NOTE: THis is not forgiving! No TCP fallback! #try: r = dns.query.udp(message, resolver,timeout=timeout) if r.flags & dns.flags.TC: logger.debug( "D: %s udp flag TC, trying tcp" % lprefix ) try: r = dns.query.tcp(message, resolver) #UTO - TCPOK except socket.error: logger.error( "E: %s tcp refused after TC flag set" % lprefix ) raise ednsException("tcp refused after TC flag set") # #else: # # UDPOK #except dns.exception.Timeout: # logger.debug( "D: %s udp timeout, trying tcp" % lprefix ) # try: # r = dns.query.tcp(message, resolver) # # TCPON # except socket.error: # logger.error( "E: %s tcp refused too" % lprefix ) # raise ednsException("tcp refused after udp timeout") records=[] for answers in r.answer: for item in answers.items: # there seems no generic way to get the payload, except using to_text # but that does not include the type of RR (e.g. CNAME) records.append( "%s %s %s" % (item.rdclass,item.rdtype,item.to_text() ) ) response={} have_csn = False for options in r.options: if isinstance(options, ClientSubnetOption): have_csn=True response['client_ip'] = cso.ip response['client_family'] = cso.family response['client_mask'] = cso.mask response['client_scope'] = options.scope if not have_csn: logger.error( "E: %s clientsubnet: FALSE" % lprefix ) raise ednsException("No csn option") #logger.debug ( "D: %s %s" % ( lprefix, str(r).splitlines() ) ) response['rcode'] = r.rcode() response['dns_results'] = r response['records'] = records return response