1*7cd94d69Schristos#!/usr/bin/env python 2*7cd94d69Schristos 3*7cd94d69Schristosimport hashlib 4*7cd94d69Schristosimport sys 5*7cd94d69Schristosimport struct 6*7cd94d69Schristosimport socket 7*7cd94d69Schristosimport time 8*7cd94d69Schristosfrom optparse import OptionParser 9*7cd94d69Schristos 10*7cd94d69Schristosimport dns.message 11*7cd94d69Schristosimport dns.name 12*7cd94d69Schristosimport dns.rdataclass 13*7cd94d69Schristosimport dns.rdatatype 14*7cd94d69Schristos 15*7cd94d69Schristosdef _calc_hashkey(qname, secret, qtype): 16*7cd94d69Schristos qclass = 'IN' # CLASS is fixed for simplicity 17*7cd94d69Schristos hobj = hashlib.sha256() 18*7cd94d69Schristos hobj.update(dns.name.from_text(qname).to_wire()) 19*7cd94d69Schristos hobj.update(struct.pack('HH', 20*7cd94d69Schristos socket.htons(dns.rdatatype.from_text(qtype)), 21*7cd94d69Schristos socket.htons(dns.rdataclass.from_text(qclass)))) 22*7cd94d69Schristos hobj.update(secret) 23*7cd94d69Schristos return hobj.hexdigest().upper() 24*7cd94d69Schristos 25*7cd94d69Schristosdef _redis_get(options, key): 26*7cd94d69Schristos import redis 27*7cd94d69Schristos return redis.Redis(options.address, int(options.port)).get(key) 28*7cd94d69Schristos 29*7cd94d69Schristosdef _dump_value(options, qname, key, value): 30*7cd94d69Schristos print(';; query=%s/IN/%s' % (qname, options.qtype)) 31*7cd94d69Schristos print(';; key=%s' % key) 32*7cd94d69Schristos if value is None: 33*7cd94d69Schristos print(';; no value') 34*7cd94d69Schristos return 35*7cd94d69Schristos if len(value) < 16: 36*7cd94d69Schristos print(';; broken value, short length: %d' % len(value)) 37*7cd94d69Schristos return 38*7cd94d69Schristos now = int(time.time()) 39*7cd94d69Schristos timestamp = struct.unpack('!Q', value[-16:-8])[0] 40*7cd94d69Schristos expire = struct.unpack('!Q', value[-8:])[0] 41*7cd94d69Schristos print(';; Now=%d, TimeStamp=%d, Expire=%d, TTL=%d' % 42*7cd94d69Schristos (now, timestamp, expire, max(expire - now, 0))) 43*7cd94d69Schristos print(dns.message.from_wire(value[:-16])) 44*7cd94d69Schristos 45*7cd94d69Schristosdef main(): 46*7cd94d69Schristos parser = OptionParser(usage='usage: %prog [options] query_name') 47*7cd94d69Schristos parser.add_option("-a", "--address", dest="address", action="store", 48*7cd94d69Schristos default='127.0.0.1', help="backend-server address", 49*7cd94d69Schristos metavar='ADDRESS') 50*7cd94d69Schristos parser.add_option("-b", "--backend", dest="backend", action="store", 51*7cd94d69Schristos default='redis', help="backend name", 52*7cd94d69Schristos metavar='BACKEND') 53*7cd94d69Schristos parser.add_option("-p", "--port", dest="port", action="store", 54*7cd94d69Schristos default='6379', help="backend-server port", 55*7cd94d69Schristos metavar='PORT') 56*7cd94d69Schristos parser.add_option("-s", "--secret", dest="secret", action="store", 57*7cd94d69Schristos default='default', help="secret seed", metavar='SECRET') 58*7cd94d69Schristos parser.add_option("-t", "--qtype", dest="qtype", action="store", 59*7cd94d69Schristos default='A', help="query RR type", metavar='QTYPE') 60*7cd94d69Schristos 61*7cd94d69Schristos (options, args) = parser.parse_args() 62*7cd94d69Schristos if len(args) < 1: 63*7cd94d69Schristos parser.error('qname is missing') 64*7cd94d69Schristos if options.backend == 'redis': 65*7cd94d69Schristos get_func = _redis_get 66*7cd94d69Schristos else: 67*7cd94d69Schristos raise Exception('unknown backend name: %s\n' % options.backend) 68*7cd94d69Schristos key = _calc_hashkey(args[0], options.secret, options.qtype) 69*7cd94d69Schristos value = get_func(options, key) 70*7cd94d69Schristos _dump_value(options, args[0], key, value) 71*7cd94d69Schristos 72*7cd94d69Schristosif __name__ == '__main__': 73*7cd94d69Schristos try: 74*7cd94d69Schristos main() 75*7cd94d69Schristos except Exception as e: 76*7cd94d69Schristos sys.stderr.write('%s\n' % e) 77*7cd94d69Schristos exit(1) 78