1245803Stheraven#!/usr/bin/env python
2330449Seadler
3330449Seadlerimport hashlib
4245803Stheravenimport sys
5245803Stheravenimport struct
6245803Stheravenimport socket
7245803Stheravenimport time
8245803Stheravenfrom optparse import OptionParser
9245803Stheraven
10245803Stheravenimport dns.message
11245803Stheravenimport dns.name
12245803Stheravenimport dns.rdataclass
13245803Stheravenimport dns.rdatatype
14245803Stheraven
15245803Stheravendef _calc_hashkey(qname, secret, qtype):
16245803Stheraven    qclass = 'IN'           # CLASS is fixed for simplicity
17245803Stheraven    hobj = hashlib.sha256()
18245803Stheraven    hobj.update(dns.name.from_text(qname).to_wire())
19245803Stheraven    hobj.update(struct.pack('HH',
20245803Stheraven                            socket.htons(dns.rdatatype.from_text(qtype)),
21245803Stheraven                            socket.htons(dns.rdataclass.from_text(qclass))))
22245803Stheraven    hobj.update(secret)
23245803Stheraven    return hobj.hexdigest().upper()
24245803Stheraven
25245803Stheravendef _redis_get(options, key):
26245803Stheraven    import redis
27245803Stheraven    return redis.Redis(options.address, int(options.port)).get(key)
28245803Stheraven
29245803Stheravendef _dump_value(options, qname, key, value):
30245803Stheraven    print(';; query=%s/IN/%s' % (qname, options.qtype))
31245803Stheraven    print(';; key=%s' % key)
32245803Stheraven    if value is None:
33245803Stheraven        print(';; no value')
34245803Stheraven        return
35245803Stheraven    if len(value) < 16:
36245839Stheraven        print(';; broken value, short length: %d' % len(value))
37245803Stheraven        return
38245839Stheraven    now = int(time.time())
39358206Skevans    timestamp = struct.unpack('!Q', value[-16:-8])[0]
40245839Stheraven    expire = struct.unpack('!Q', value[-8:])[0]
41345881Skevans    print(';; Now=%d, TimeStamp=%d, Expire=%d, TTL=%d' %
42245803Stheraven          (now, timestamp, expire, max(expire - now, 0)))
43318093Sgonzo    print(dns.message.from_wire(value[:-16]))
44245839Stheraven
45345881Skevansdef main():
46345881Skevans    parser = OptionParser(usage='usage: %prog [options] query_name')
47345881Skevans    parser.add_option("-a", "--address", dest="address", action="store",
48345881Skevans                      default='127.0.0.1', help="backend-server address",
49345881Skevans                      metavar='ADDRESS')
50345881Skevans    parser.add_option("-b", "--backend", dest="backend", action="store",
51345881Skevans                      default='redis', help="backend name",
52345881Skevans                      metavar='BACKEND')
53345881Skevans    parser.add_option("-p", "--port", dest="port", action="store",
54345881Skevans                      default='6379', help="backend-server port",
55345881Skevans                      metavar='PORT')
56345881Skevans    parser.add_option("-s", "--secret", dest="secret", action="store",
57345881Skevans                      default='default', help="secret seed", metavar='SECRET')
58345881Skevans    parser.add_option("-t", "--qtype", dest="qtype", action="store",
59345881Skevans                      default='A', help="query RR type", metavar='QTYPE')
60345881Skevans
61345881Skevans    (options, args) = parser.parse_args()
62345881Skevans    if len(args) < 1:
63345881Skevans        parser.error('qname is missing')
64345881Skevans    if options.backend == 'redis':
65345881Skevans        get_func = _redis_get
66345881Skevans    else:
67345881Skevans        raise Exception('unknown backend name: %s\n' % options.backend)
68245803Stheraven    key = _calc_hashkey(args[0], options.secret, options.qtype)
69245803Stheraven    value = get_func(options, key)
70245803Stheraven    _dump_value(options, args[0], key, value)
71245803Stheraven
72245803Stheravenif __name__ == '__main__':
73245803Stheraven    try:
74245803Stheraven        main()
75289935Stheraven    except Exception as e:
76245803Stheraven        sys.stderr.write('%s\n' % e)
77289935Stheraven        exit(1)
78245803Stheraven