Initial import
[ldd.git] / dnsdbtool
1 #!/usr/bin/python
2 #    ldd - DNS implementation in Python
3 #    Copyright (C) 2006 Fredrik Tolf <fredrik@dolda2000.com>
4 #
5 #    This program is free software; you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License as published by
7 #    the Free Software Foundation; either version 2 of the License, or
8 #    (at your option) any later version.
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program; if not, write to the Free Software
17 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19
20 import sys
21 from getopt import getopt
22 import socket
23
24 from ldd import dbzone, rec, dn
25
26 if len(sys.argv) < 3:
27     print "usage: dnsdbtool [-d] DBDIR DBNAME [COMMAND [ARGS...]]"
28     print "       dnsdbtool -c DBDIR DBNAME"
29     sys.exit(1)
30
31 debug = False
32 currrset = None
33 curname = None
34 opts, args = getopt(sys.argv[1:], "cd")
35 for o, a in opts:
36     if o == "-c":
37         dbzone.dnsdb.create(args[0], args[1])
38         sys.exit(0)
39     if o == "-d":
40         debug = True
41
42 db = dbzone.dnsdb(args[0], args[1])
43
44 args = args[2:]
45
46 class error(Exception):
47     def __init__(self, text):
48         self.text = text
49
50     def __str__(self):
51         return self.text
52
53 def rrusage(name, syn):
54     u = ""
55     for e in syn:
56         u += " " + e[1].upper()
57     return "usage: " + name + u
58
59 def mkrr(line):
60     rtype = rec.rtypebyname(line[0])
61     if rtype is None:
62         raise error("no such RR type " + line[0])
63     rtype = rec.rtypebyid(rtype)
64     syn = rtype[2]
65     if(len(line) != len(syn) + 1):
66         raise error(rrusage(rtype[1], syn))
67     return rec.rrdata(*line)
68
69 def tokenize(line):
70     tokens = []
71     state = 0
72     for c in line + " ":
73         if state == 0:
74             if not c.isspace():
75                 ctok = ""
76                 state = 1
77         if state == 1:
78             if c.isspace():
79                 tokens += [ctok]
80                 state = 0
81             elif c == '"':
82                 state = 2
83             elif c == "\\":
84                 state = 3
85             else:
86                 ctok += c
87         elif state == 2:
88             if c == '"':
89                 state = 1
90             elif c == "\\":
91                 state = 4
92             else:
93                 ctok += c
94         elif state == 3:
95             ctok += c
96             state = 1
97         elif state == 4:
98             ctok += c
99             state = 2
100     return tokens
101
102 def assertargs(cmd, line, num, usage):
103     if(len(line) < num):
104         raise error("usage: " + cmd + " " + usage)
105
106 def runcommand(line):
107     global currrset, curname
108     cmd = line[0]
109     line = line[1:]
110     if cmd == "addnm":
111         assertargs(cmd, line, 3, "[-f FLAG] NAME TTL RR RRPARAM...")
112         opts, line = getopt(line, "f:")
113         opts = dict(opts)
114         head = rec.rrhead(dn.fromstring(line[0]), line[2])
115         ttl = int(line[1])
116         data = mkrr(line[2:])
117         rr = rec.rr(head, ttl, data)
118         if "-f" in opts: rr.setflags(opts["-f"].split(","))
119         db.addrr(head.name, rr)
120     elif cmd == "rmname":
121         assertargs(cmd, line, 1, "NAME")
122         name = dn.fromstring(line[0])
123         db.rmname(name)
124     elif cmd == "rmrt":
125         assertargs(cmd, line, 2, "NAME RRTYPE")
126         name = dn.fromstring(line[0])
127         db.rmrtype(name, line[1])
128     elif cmd == "lsnames":
129         for name in db.listnames():
130             print str(name)
131     elif cmd == "lsrr":
132         assertargs(cmd, line, 1, "NAME")
133         name = dn.fromstring(line[0])
134         rrset = db.lookup(name)
135 #        dbzone.rootify(rrset, dn.fromstring("dolda2000.com."))
136         if rrset is None:
137             raise error("no such name in database")
138         for rr in rrset:
139             print str(rr)
140     elif cmd == "load":
141         assertargs(cmd, line, 1, "NAME")
142         name = dn.fromstring(line[0])
143         currrset = db.lookup(name)
144         curname = name
145         if currrset is None:
146             currrset = []
147     elif cmd == "add":
148         assertargs(cmd, line, 2, "[-f FLAG] TTL RR RRPARAM...")
149         opts, line = getopt(line, "f:")
150         opts = dict(opts)
151         head = rec.rrhead(curname, line[1])
152         ttl = int(line[0])
153         data = mkrr(line[1:])
154         rr = rec.rr(head, ttl, data)
155         if "-f" in opts: rr.setflags(opts["-f"].split(","))
156         currrset += [rr]
157     elif cmd == "ls":
158         if currrset is None:
159             raise error("no RRset loaded")
160         for i, rr in enumerate(currrset):
161             print str(i) + ": " + str(rr)
162     elif cmd == "rm":
163         assertargs(cmd, line, 1, "ID")
164         rrid = int(line[0])
165         currrset[rrid:rrid + 1] = []
166     elif cmd == "chttl":
167         assertargs(cmd, line, 2, "ID NEWTTL")
168         rrid = int(line[0])
169         ttl = int(line[1])
170         currrset[rrid].head.ttl = ttl
171     elif cmd == "chdt":
172         assertargs(cmd, line, 3, "ID NAME DATA")
173         rrid = int(line[0])
174         currrset[rrid].data[line[1]] = line[2]
175     elif cmd == "sf":
176         assertargs(cmd, line, 2, "ID FLAGS...")
177         rrid = int(line[0])
178         currrset[rrid].setflags(line[1:])
179     elif cmd == "cf":
180         assertargs(cmd, line, 2, "ID FLAGS...")
181         rrid = int(line[0])
182         currrset[rrid].clrflags(line[1:])
183     elif cmd == "store":
184         if len(line) > 0:
185             name = line[0]
186         else:
187             name = curname
188         db.set(name, currrset)
189     elif cmd == "?" or cmd == "help":
190         print "Available commands:"
191         print "addnm, rmname, rmrt, lsnames, lsrr, load, add, ls, rm,"
192         print "chttl, chdt, sf, cf, store"
193     else:
194         print "no such command: " + cmd
195
196 if len(args) == 0:
197     while True:
198         if sys.stdin.isatty():
199             sys.stderr.write("> ")
200         line = sys.stdin.readline()
201         if line == "":
202             if sys.stdin.isatty(): print
203             break
204         try:
205             tokens = tokenize(line)
206             if len(tokens) > 0: runcommand(tokens)
207         except error:
208             sys.stderr.write(str(sys.exc_info()[1]) + "\n")
209 else:
210     try:
211         runcommand(args)
212     except SystemExit:
213         raise
214     except:
215         if debug:
216             raise
217         else:
218             sys.stderr.write(str(sys.exc_info()[1]) + "\n")