Initial import
[ldd.git] / ldd / filters.py
1 #    ldd - DNS implementation in Python
2 #    Copyright (C) 2006 Fredrik Tolf <fredrik@dolda2000.com>
3 #
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.
8 #
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.
13 #
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
17
18 import socket
19 import time
20 import fcntl
21 import struct
22
23 import server
24
25 def linuxifip4hack(ifname):
26     req = ifname + ("\0" * (32 - len(ifname)))
27     sk = socket.socket()
28     res = fcntl.ioctl(sk.fileno(), 0x8915, req)
29     sk.close()
30     sockaddr = res[16:]
31     return sockaddr[4:8]
32
33 class valuecache:
34     def __init__(self, func, expire):
35         self.func = func
36         self.expire = expire
37         self.last = 0
38
39     def __call__(self, *args):
40         now = int(time.time())
41         if self.last == 0 or now - self.last > self.expire:
42             self.val = self.func(*(args))
43             self.last = now
44         return self.val
45
46 class prefix6to4(server.handler):
47     def __init__(self, next, v4addr):
48         self.next = next
49         if callable(v4addr):
50             self.packed = v4addr
51         elif len(v4addr) == 4:
52             self.packed = v4addr
53         else:
54             self.packed = socket.inet_pton(socket.AF_INET, v4addr)
55
56     def handle(self, *args):
57         resp = self.next.handle(*args)
58         if resp is None:
59             return None
60         for rr in resp.allrrs():
61             if rr.head.istype("AAAA"):
62                 addr = rr.data["address"]
63                 if addr[0:6] == "\x20\x02\x00\x00\x00\x00":
64                     packed = self.packed
65                     if callable(packed):
66                         packed = packed()
67                     addr = addr[0:2] + packed + addr[6:]
68                     rr.data["address"] = addr
69         return resp
70
71 class addrfilter(server.handler):
72     def __init__(self, default = None, matchers = []):
73         self.matchers = matchers
74         self.default = default
75
76     def setdefault(self, handler):
77         self.default = handler
78
79     def addmatcher(self, af, prefix, preflen, handler):
80         self.matchers += [(af, socket.inet_pton(af, prefix), preflen, handler)]
81     
82     def handle(self, query, pkt, origin):
83         matchlen = -1
84         match = self.default
85         if pkt.addr is not None:
86             for af, prefix, preflen, handler in self.matchers:
87                 if pkt.addr[0] == af:
88                     addr = socket.inet_pton(af, pkt.addr[1])
89                     bytes = preflen >> 3
90                     restmask = 255 ^ ((1 << (8 - (preflen & 7))) - 1)
91                     if prefix[0:bytes] == addr[0:bytes] and \
92                            (ord(prefix[bytes]) & restmask) == (ord(addr[bytes]) & restmask):
93                         if preflen > matchlen:
94                             matchlen = preflen
95                             match = handler
96         if match is not None:
97             return match.handle(query, pkt, origin)
98         return None