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