1 # ldd - DNS implementation in Python
2 # Copyright (C) 2006 Fredrik Tolf <fredrik@dolda2000.com>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 def addrtype(id, name, syntax):
27 rtypes.append((id, name, syntax))
35 def rtypebyname(name):
37 if rtype[1] == name.upper():
41 class error(Exception):
42 def __init__(self, text):
48 class malformedrr(Exception):
49 def __init__(self, text):
56 def __init__(self, name = None, rtype = None, rclass = None):
57 if rclass is None: rclass = CLASSIN
59 self.name = dn.fromstring(name)
62 if type(rtype) == str:
63 self.rtype = rtypebyname(rtype)
64 if self.rtype is None:
65 raise error("no such rtype " + rtype)
70 def encode(self, names, offset):
71 ret, names = proto.encodename(self.name, names, offset)
72 ret += struct.pack(">HH", self.rtype, self.rclass)
75 def __eq__(self, other):
76 return self.name == other.name and self.rtype == other.rtype
79 rtype = rtypebyid(self.rtype)
81 return "%02x RRhead %s" % (self.rtype, self.name)
83 return "%s RRhead %s" % (rtype[1], self.name)
85 def istype(self, rtype):
86 if type(rtype) == str:
87 rtype = rtypebyname(rtype)
88 return self.rtype == rtype
90 def decode(self, packet, offset):
91 name, offset = proto.decodename(packet, offset)
92 rtype, rclass = struct.unpack(">HH", packet[offset:offset + struct.calcsize(">HH")])
93 offset += struct.calcsize(">HH")
94 ret = rrhead(name, rtype, rclass)
96 decode = classmethod(decode)
99 def __init__(self, rtype, *args):
100 if type(rtype) == tuple and type(args[0]) == dict:
105 if type(rtype) == str:
106 self.rtype = rtypebyname(rtype)
107 if self.rtype is None:
108 raise error("no such rtype " + rtype)
112 self.rtype = rtypebyid(rtid)
113 if self.rtype is None:
114 raise error("no such rtype " + rtid)
116 for i, e in enumerate(self.rtype[2]):
117 d = self.convdata(e[0], args[i])
120 def __eq__(self, other):
121 return(self.rdata == other.rdata)
126 for e in self.rtype[2]:
133 ret += socket.inet_ntop(socket.AF_INET, d)
135 ret += socket.inet_ntop(socket.AF_INET6, d)
143 def istype(self, rtype):
144 if type(rtype) == str:
145 rtype = rtypebyname(rtype)
146 return self.rtype[0] == rtype
148 def convdata(self, dtype, data):
150 if type(data) != str:
151 raise error("IPv4 address must be a string")
155 d = socket.inet_pton(socket.AF_INET, data)
157 if type(data) != str:
158 raise error("IPv6 address must be a string")
159 if len(data) == 16 and data.find(":") == -1:
162 d = socket.inet_pton(socket.AF_INET6, data)
164 if type(data) == str:
165 d = dn.fromstring(data)
166 elif isinstance(data, dn.domainname):
169 raise error("Domain name must be either proper or string")
177 return iter(self.rdata)
179 def __getitem__(self, i):
182 def __setitem__(self, i, v):
183 for e in self.rtype[2]:
187 raise error("No such data for " + self.rtype[1] + " record: " + str(i))
188 self.rdata[i] = self.convdata(e[0], v)
190 def encode(self, names, offset):
192 for e in self.rtype[2]:
198 buf, names = proto.encodename(d, names, offset)
202 ret += chr(len(d)) + d
205 ret += struct.pack(">H", len(d)) + d
206 offset += struct.calcsize(">H") + len(d)
208 ret += struct.pack(">H", d)
209 offset += struct.calcsize(">H")
211 ret += struct.pack(">L", d)
212 offset += struct.calcsize(">L")
214 ret += struct.pack(">Q", d)[-6:]
218 def decode(self, rtid, packet, offset, dlen):
219 rtype = rtypebyid(rtid)
223 rtype = (rtid, "Unknown", [("s", "unknown", "strc", dlen)])
226 d = packet[offset:offset + e[3]]
229 d, offset = proto.decodename(packet, offset)
231 dl = ord(packet[offset])
233 d = packet[offset:offset + dl]
236 (dl,) = struct.unpack(">H", packet[offset:offset + struct.calcsize(">H")])
237 offset += struct.calcsize(">H")
238 d = packet[offset:offset + dl]
241 (d,) = struct.unpack(">H", packet[offset:offset + struct.calcsize(">H")])
242 offset += struct.calcsize(">H")
244 (d,) = struct.unpack(">L", packet[offset:offset + struct.calcsize(">L")])
245 offset += struct.calcsize(">L")
247 (d,) = struct.unpack(">Q", ("\0" * (struct.calcsize(">Q") - 6)) + packet[offset:offset + 6])
250 if origoff + dlen != offset:
251 raise malformedrr(rtype[1] + " RR data length mismatch")
252 return rrdata(rtype, rdata)
253 decode = classmethod(decode)
256 def __init__(self, head, ttl, data):
257 if type(head) == tuple:
258 self.head = rrhead(*head)
265 def setflags(self, flags):
266 self.flags |= set(flags)
268 def clrflags(self, flags):
269 self.flags -= set(flags)
271 def encode(self, names, offset):
272 ret, names = self.head.encode(names, offset)
273 if self.data is None:
276 data, names = self.data.encode(names, offset + len(ret) + struct.calcsize(">LH"))
277 ret += struct.pack(">LH", self.ttl, len(data))
281 def __eq__(self, other):
282 return self.head == other.head and self.ttl == other.ttl and self.data == other.data
285 rtype = rtypebyid(self.head.rtype)
287 ret = "%02x" % self.head.rtype
290 ret += " RR %s, TTL=%i: %s" % (self.head.name, self.ttl, self.data)
291 if len(self.flags) > 0:
298 def decode(self, packet, offset):
299 head, offset = rrhead.decode(packet, offset)
300 ttl, dlen = struct.unpack(">LH", packet[offset:offset + struct.calcsize(">LH")])
301 offset += struct.calcsize(">LH")
305 data = rrdata.decode(head.rtype, packet, offset, dlen)
307 return rr(head, ttl, data), offset
308 decode = classmethod(decode)
310 addrtype(0x01, "A", [("4", "address", "strc", 4)])
311 addrtype(0x02, "NS", [("d", "nsname", "cmdn")])
312 addrtype(0x05, "CNAME", [("d", "priname", "cmdn")])
313 addrtype(0x06, "SOA", [("d", "priserv", "cmdn"),
314 ("d", "mailbox", "cmdn"),
315 ("i", "serial", "long"),
316 ("i", "refresh", "long"),
317 ("i", "retry", "long"),
318 ("i", "expire", "long"),
319 ("i", "minttl", "long")])
320 addrtype(0x0c, "PTR", [("d", "target", "cmdn")])
321 addrtype(0x0f, "MX", [("i", "prio", "short"),
322 ("d", "target", "cmdn")])
323 addrtype(0x10, "TXT", [("s", "rrtext", "lstr")])
324 addrtype(0x1c, "AAAA", [("6", "address", "strc", 16)])
325 addrtype(0x21, "SRV", [("i", "prio", "short"),
326 ("i", "weight", "short"),
327 ("i", "port", "short"),
328 ("d", "target", "cmdn")])
329 addrtype(0xfa, "TSIG", [("d", "algo", "cmdn"),
330 ("i", "stime", "int6"),
331 ("i", "fudge", "short"),
332 ("s", "mac", "llstr"),
333 ("i", "orgid", "short"),
334 ("i", "err", "short"),
335 ("s", "other", "llstr")])