Initial import
[ldd.git] / dnsdbtool
CommitLineData
769e7ed9 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
20import sys
21from getopt import getopt
22import socket
23
24from ldd import dbzone, rec, dn
25
26if len(sys.argv) < 3:
27 print "usage: dnsdbtool [-d] DBDIR DBNAME [COMMAND [ARGS...]]"
28 print " dnsdbtool -c DBDIR DBNAME"
29 sys.exit(1)
30
31debug = False
32currrset = None
33curname = None
34opts, args = getopt(sys.argv[1:], "cd")
35for 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
42db = dbzone.dnsdb(args[0], args[1])
43
44args = args[2:]
45
46class error(Exception):
47 def __init__(self, text):
48 self.text = text
49
50 def __str__(self):
51 return self.text
52
53def rrusage(name, syn):
54 u = ""
55 for e in syn:
56 u += " " + e[1].upper()
57 return "usage: " + name + u
58
59def 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
69def 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
102def assertargs(cmd, line, num, usage):
103 if(len(line) < num):
104 raise error("usage: " + cmd + " " + usage)
105
106def 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
196if 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")
209else:
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")