Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / names / tap.py
1 # -*- test-case-name: twisted.names.test.test_tap -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Domain Name Server
7 """
8
9 import os, traceback
10
11 from twisted.python import usage
12 from twisted.names import dns
13 from twisted.application import internet, service
14
15 from twisted.names import server
16 from twisted.names import authority
17 from twisted.names import secondary
18
19 class Options(usage.Options):
20     optParameters = [
21         ["interface", "i", "",   "The interface to which to bind"],
22         ["port",      "p", "53", "The port on which to listen"],
23         ["resolv-conf", None, None,
24             "Override location of resolv.conf (implies --recursive)"],
25         ["hosts-file", None, None, "Perform lookups with a hosts file"],
26     ]
27
28     optFlags = [
29         ["cache",       "c", "Enable record caching"],
30         ["recursive",   "r", "Perform recursive lookups"],
31         ["verbose",     "v", "Log verbosely"],
32     ]
33
34     compData = usage.Completions(
35         optActions={"interface" : usage.CompleteNetInterfaces()}
36         )
37
38     zones = None
39     zonefiles = None
40
41     def __init__(self):
42         usage.Options.__init__(self)
43         self['verbose'] = 0
44         self.bindfiles = []
45         self.zonefiles = []
46         self.secondaries = []
47
48
49     def opt_pyzone(self, filename):
50         """Specify the filename of a Python syntax zone definition"""
51         if not os.path.exists(filename):
52             raise usage.UsageError(filename + ": No such file")
53         self.zonefiles.append(filename)
54
55     def opt_bindzone(self, filename):
56         """Specify the filename of a BIND9 syntax zone definition"""
57         if not os.path.exists(filename):
58             raise usage.UsageError(filename + ": No such file")
59         self.bindfiles.append(filename)
60
61
62     def opt_secondary(self, ip_domain):
63         """Act as secondary for the specified domain, performing
64         zone transfers from the specified IP (IP/domain)
65         """
66         args = ip_domain.split('/', 1)
67         if len(args) != 2:
68             raise usage.UsageError("Argument must be of the form IP[:port]/domain")
69         address = args[0].split(':')
70         if len(address) == 1:
71             address = (address[0], dns.PORT)
72         else:
73             try:
74                 port = int(address[1])
75             except ValueError:
76                 raise usage.UsageError(
77                     "Specify an integer port number, not %r" % (address[1],))
78             address = (address[0], port)
79         self.secondaries.append((address, [args[1]]))
80
81
82     def opt_verbose(self):
83         """Increment verbosity level"""
84         self['verbose'] += 1
85
86
87     def postOptions(self):
88         if self['resolv-conf']:
89             self['recursive'] = True
90
91         self.svcs = []
92         self.zones = []
93         for f in self.zonefiles:
94             try:
95                 self.zones.append(authority.PySourceAuthority(f))
96             except Exception:
97                 traceback.print_exc()
98                 raise usage.UsageError("Invalid syntax in " + f)
99         for f in self.bindfiles:
100             try:
101                 self.zones.append(authority.BindAuthority(f))
102             except Exception:
103                 traceback.print_exc()
104                 raise usage.UsageError("Invalid syntax in " + f)
105         for f in self.secondaries:
106             svc = secondary.SecondaryAuthorityService.fromServerAddressAndDomains(*f)
107             self.svcs.append(svc)
108             self.zones.append(self.svcs[-1].getAuthority())
109         try:
110             self['port'] = int(self['port'])
111         except ValueError:
112             raise usage.UsageError("Invalid port: %r" % (self['port'],))
113
114
115 def _buildResolvers(config):
116     """
117     Build DNS resolver instances in an order which leaves recursive
118     resolving as a last resort.
119
120     @type config: L{Options} instance
121     @param config: Parsed command-line configuration
122
123     @return: Two-item tuple of a list of cache resovers and a list of client
124         resolvers
125     """
126     from twisted.names import client, cache, hosts
127
128     ca, cl = [], []
129     if config['cache']:
130         ca.append(cache.CacheResolver(verbose=config['verbose']))
131     if config['hosts-file']:
132         cl.append(hosts.Resolver(file=config['hosts-file']))
133     if config['recursive']:
134         cl.append(client.createResolver(resolvconf=config['resolv-conf']))
135     return ca, cl
136
137
138 def makeService(config):
139     ca, cl = _buildResolvers(config)
140
141     f = server.DNSServerFactory(config.zones, ca, cl, config['verbose'])
142     p = dns.DNSDatagramProtocol(f)
143     f.noisy = 0
144     ret = service.MultiService()
145     for (klass, arg) in [(internet.TCPServer, f), (internet.UDPServer, p)]:
146         s = klass(config['port'], arg, interface=config['interface'])
147         s.setServiceParent(ret)
148     for svc in config.svcs:
149         svc.setServiceParent(ret)
150     return ret