Skip to content

Commit c70419f

Browse files
author
fangshaosen
committed
frist commit all files
1 parent 76bec69 commit c70419f

58 files changed

Lines changed: 143785 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
log/*

bin/.dnsserver.py.swp

20 KB
Binary file not shown.

bin/checkconfig.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import sys, os
4+
import traceback
5+
from os.path import isfile
6+
sys.path.append('../lib')
7+
import yaml
8+
9+
def loadconfig(path):
10+
if not isfile(path):
11+
print "[FATAL] can't find config file %s !" % path
12+
exit(1)
13+
f = open(path, 'r')
14+
x = yaml.load(f)
15+
f.close
16+
return x
17+
18+
def checkDnsMainConfig(c):
19+
if c['dnsforward_port'] not in range(1, 65536):
20+
print "[FATAL] dnsforward_port out of range."
21+
return False
22+
for ip in c['dnsforward_ip']:
23+
boollist = map(lambda x: -1<x<256,map(int,ip.split('.')))
24+
if len(boollist) != 4 or not all(boollist):
25+
print "[FATAL] dnsforward_ip config error"
26+
return False
27+
print "[INFO] 'dns MAIN' configuration check succ"
28+
return True
29+
30+
def checkAmapConfig(c):
31+
for url,ref in c.items():
32+
#must have 'default' and 'ttl' in every url
33+
if ref['default'] and "" == ref['default']:
34+
print "[FATAL] default value is Null"
35+
return False
36+
int(ref['ttl'])
37+
for rl,ip in ref.items():
38+
if rl in ['default', 'ttl']:
39+
continue
40+
if (len(rl.split(',')) != 4):
41+
print "[FATAL] bucket ip refer error"
42+
return False
43+
print "[INFO] 'A' configuration check succ"
44+
return True
45+
46+
def checkNSmapConfig(c):
47+
for url,ref in c.items():
48+
#must have 'record' and 'ttl' in every url
49+
ref['record']
50+
int(ref['ttl'])
51+
print "[INFO] 'NS' configuration check succ"
52+
return True
53+
54+
def checkSOAmapConfig(c):
55+
for url,ref in c.items():
56+
#must have 'record' and 'ttl' in every url
57+
ref['record']
58+
ref['email']
59+
ref['serial']
60+
int(ref['refresh'])
61+
int(ref['retry'])
62+
int(ref['expire'])
63+
int(ref['ttl'])
64+
print "[INFO] 'SOA' configuration check succ"
65+
return True
66+
67+
def checkIPList(ipfile):
68+
''' 判断ip列表是否有重合的部分 '''
69+
iphash = {}
70+
iplist = []
71+
f = open(ipfile, 'r')
72+
for eachline in f:
73+
ipstart, ipend, country, province, city, sp = eachline.strip().split(',')
74+
ipstart = long(ipstart)
75+
ipend = long(ipend)
76+
if ipstart > ipend:
77+
print "[ERROR] ip starts(%s) bigger than ends(%s)" %(ipstart, ipend)
78+
return False
79+
if 0 == ipstart:
80+
print "[ERROR] ip starts with 0"
81+
return False
82+
if ipstart in iphash:
83+
print "[ERROR] ip起始点重合:start(%s),end(%s)" % (ipstart, ipend)
84+
return False
85+
iplist.append(ipstart)
86+
iphash[ipstart] = ipend
87+
iplist.sort()
88+
i = 0
89+
length = len(iplist) - 1
90+
while i < length:
91+
if iphash[iplist[i]] >= iplist[i + 1]:
92+
print "[ERROR] ip有重合,start(%s),end(%s)和start(%s),end(%s)" % \
93+
( iplist[i], iphash[iplist[i]], iplist[i+1], iphash[iplist[i+1]])
94+
return False
95+
i += 1
96+
print "[INFO] 'IP.CSV' configuration check succ"
97+
return True
98+
99+
def checkconfig():
100+
#main config
101+
try:
102+
conf = loadconfig('../conf/sdns.yaml')
103+
if not checkDnsMainConfig(conf):
104+
return False
105+
106+
#dns record config file
107+
Amapping = loadconfig(conf['AFILE'])
108+
NSmapping = loadconfig(conf['NSFILE'])
109+
SOAmapping = loadconfig(conf['SOAFILE'])
110+
if not checkAmapConfig(Amapping) or not checkNSmapConfig(NSmapping) or not checkSOAmapConfig(SOAmapping):
111+
return False
112+
if not checkIPList("../data/ip.csv"):
113+
return False
114+
return True
115+
except:
116+
print traceback.print_exc()
117+
return False
118+
119+
if __name__ == '__main__':
120+
print "[INFO] start check configuration"
121+
if not checkconfig():
122+
print "\x1b[1;31m[FATAL] check configuration failed.\x1b[0m"
123+
sys.exit(1)
124+
print "[INFO] check configuration done, all ok."

bin/dnsserver.py

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# -*- coding: utf-8 -*-
2+
import sys, os
3+
import random
4+
import re
5+
import time
6+
import inspect
7+
from logger import logger
8+
sys.path.append('../lib')
9+
from twisted.names import dns, server, client, cache, common, resolve
10+
from twisted.python import failure
11+
from twisted.internet import defer
12+
13+
typeToMethod = {
14+
dns.A: 'lookupAddress',
15+
dns.AAAA: 'lookupIPV6Address',
16+
dns.A6: 'lookupAddress6',
17+
dns.NS: 'lookupNameservers',
18+
dns.CNAME: 'lookupCanonicalName',
19+
dns.SOA: 'lookupAuthority',
20+
dns.MB: 'lookupMailBox',
21+
dns.MG: 'lookupMailGroup',
22+
dns.MR: 'lookupMailRename',
23+
dns.NULL: 'lookupNull',
24+
dns.WKS: 'lookupWellKnownServices',
25+
dns.PTR: 'lookupPointer',
26+
dns.HINFO: 'lookupHostInfo',
27+
dns.MINFO: 'lookupMailboxInfo',
28+
dns.MX: 'lookupMailExchange',
29+
dns.TXT: 'lookupText',
30+
dns.SPF: 'lookupSenderPolicy',
31+
32+
dns.RP: 'lookupResponsibility',
33+
dns.AFSDB: 'lookupAFSDatabase',
34+
dns.SRV: 'lookupService',
35+
dns.NAPTR: 'lookupNamingAuthorityPointer',
36+
dns.AXFR: 'lookupZone',
37+
dns.ALL_RECORDS: 'lookupAllRecords',
38+
}
39+
40+
smartType = ('lookupAddress', 'lookupAuthority')
41+
42+
class FailureHandler:
43+
def __init__(self, resolver, query, timeout, addr = None, edns = None):
44+
self.resolver = resolver
45+
self.query = query
46+
self.timeout = timeout
47+
self.addr = addr
48+
self.edns = edns
49+
50+
def __call__(self, failure):
51+
# AuthoritativeDomainErrors should halt resolution attempts
52+
failure.trap(dns.DomainError, defer.TimeoutError, NotImplementedError)
53+
return self.resolver(self.query, self.timeout, self.addr, self.edns)
54+
55+
56+
class MapResolver(client.Resolver):
57+
def __init__(self, Finder, Amapping, NSmapping, SOAmapping, servers):
58+
self.Finder = Finder
59+
self.Amapping = Amapping
60+
self.NSmapping = NSmapping
61+
self.SOAmapping = SOAmapping
62+
client.Resolver.__init__(self, servers=servers)
63+
64+
def query(self, query, timeout = None, addr = None, edns = None):
65+
try:
66+
if typeToMethod[query.type] in smartType:
67+
return self.typeToMethod[query.type](str(query.name), timeout, addr, edns)
68+
else:
69+
return self.typeToMethod[query.type](str(query.name), timeout)
70+
except KeyError, e:
71+
return defer.fail(failure.Failure(NotImplementedError(str(self.__class__) + " " + str(query.type))))
72+
73+
def lookupAddress(self, name, timeout = None, addr = None, edns = None):
74+
if name in self.Amapping:
75+
ttl = self.Amapping[name]['ttl']
76+
def packResult( value ):
77+
ret = []
78+
add = []
79+
for x in value:
80+
ret.append(dns.RRHeader(name, dns.A, dns.IN, ttl, dns.Record_A(x, ttl), True))
81+
82+
if edns is not None:
83+
if edns.rdlength > 8:
84+
add.append(dns.RRHeader('', dns.EDNS, 4096, edns.ttl, edns.payload, True))
85+
else:
86+
add.append(dns.RRHeader('', dns.EDNS, 4096, 0, dns.Record_EDNS(None, 0), True))
87+
return [ret, (), add]
88+
89+
result = self.Finder.FindIP(str(addr[0]), name)
90+
#返回的IP数组乱序
91+
random.shuffle(result)
92+
return packResult(result)
93+
else:
94+
return self._lookup(name, dns.IN, dns.A, timeout)
95+
96+
def lookupNameservers(self, name, timeout=None):
97+
if name in self.NSmapping:
98+
result = self.NSmapping[name]
99+
ttl = result['ttl']
100+
record = re.split(ur',|\s+', result['record'])
101+
def packResultNS(value):
102+
ret = []
103+
for x in value:
104+
ret.append(dns.RRHeader(name, dns.NS, dns.IN, ttl, dns.Record_NS(x, ttl), True))
105+
return [ret, (), ()]
106+
return packResultNS(record)
107+
else:
108+
return self._lookup(name, dns.IN, dns.NS, timeout)
109+
110+
def lookupAuthority(self, name, timeout=None, addr = None, edns = None):
111+
if name in self.SOAmapping:
112+
result = self.SOAmapping[name]
113+
add = []
114+
def packResultSOA(value):
115+
if edns is not None:
116+
if edns.rdlength > 8:
117+
add.append(dns.RRHeader('', dns.EDNS, 4096, edns.ttl, edns.payload, True))
118+
else:
119+
add.append(dns.RRHeader('', dns.EDNS, 4096, 0, dns.Record_EDNS(None, 0), True))
120+
121+
return [(dns.RRHeader(name, dns.SOA, dns.IN, value['ttl'], dns.Record_SOA(value['record'], value['email'], value['serial'], value['refresh'], value['retry'], value['expire'], value['ttl']), True),),
122+
(),
123+
add
124+
]
125+
ret = packResultSOA(result)
126+
logger.info("SOA\t[domain: %s]\t[return: %s]\t[additional: %s]" % \
127+
(name, result, add))
128+
return ret
129+
else:
130+
return self._lookup(name, dns.IN, dns.SOA, timeout)
131+
132+
def lookupIPV6Address(self, name, timeout = None, addr = None):
133+
return [(),(),()]
134+
135+
class SmartResolverChain(resolve.ResolverChain):
136+
137+
def __init__(self, resolvers):
138+
#resolve.ResolverChain.__init__(self, resolvers)
139+
common.ResolverBase.__init__(self)
140+
self.resolvers = resolvers
141+
142+
def _lookup(self, name, cls, type, timeout, addr = None, edns = None):
143+
q = dns.Query(name, type, cls)
144+
#d = self.resolvers[0].query(q, timeout)
145+
d = defer.fail(failure.Failure(dns.DomainError(name)))
146+
for r in self.resolvers[1:]:
147+
d = d.addErrback(
148+
FailureHandler(r.query, q, timeout, addr, edns)
149+
)
150+
return d
151+
152+
def query(self, query, timeout = None, addr = None, edns = None):
153+
try:
154+
if typeToMethod[query.type] in smartType:
155+
return self.typeToMethod[query.type](str(query.name), timeout, addr, edns)
156+
else:
157+
return self.typeToMethod[query.type](str(query.name), timeout)
158+
except KeyError, e:
159+
return defer.fail(failure.Failure(NotImplementedError(str(self.__class__) + " " + str(query.type))))
160+
161+
def lookupAddress(self, name, timeout = None, addr = None, edns = None):
162+
return self._lookup(name, dns.IN, dns.A, timeout, addr, edns)
163+
164+
def lookupAuthority(self, name, timeout=None, addr = None, edns = None):
165+
return self._lookup(name, dns.IN, dns.SOA, timeout, addr, edns)
166+
167+
def lookupIPV6Address(self, name, timeout = None, addr = None, edns = None):
168+
return self._lookup(name, dns.IN, dns.AAAA, timeout, addr, edns)
169+
170+
def lookupNameservers(self, name, timeout = None, addr = None, edns = None):
171+
return self._lookup(name, dns.IN, dns.NS, timeout, addr, edns)
172+
173+
class SmartDNSFactory(server.DNSServerFactory):
174+
def handleQuery(self, message, protocol, address):
175+
#if len(message.additional) > 0:
176+
# print inspect.getmembers(message.additional[0]
177+
# 可以支持多个query
178+
query = message.queries[0]
179+
edns = None
180+
cliAddr = address
181+
if query.type == 43 or typeToMethod[query.type] == 'lookupAllRecords':
182+
return [(),(),()]
183+
if typeToMethod[query.type] in smartType and \
184+
len(message.additional) != 0 and \
185+
message.additional[0].type == 41 \
186+
and message.additional[0].rdlength > 8:
187+
cliAddr = (message.additional[0].payload.dottedQuad(), 0)
188+
edns = message.additional[0]
189+
logger.info("[type: %s]\t[protocol: %s]\t[query: %s]\t[address: %s]\t[dns_server_addr: %s]\t[additional: %s]" % \
190+
(typeToMethod[query.type], type(protocol), query, cliAddr[0], address[0], edns))
191+
return self.resolver.query(query, addr = cliAddr, edns = edns).addCallback(
192+
self.gotResolverResponse, protocol, message, address
193+
).addErrback(
194+
self.gotResolverError, protocol, message, address
195+
)
196+
197+
def __init__(self, authorities = None, caches = None, clients = None, verbose = 0):
198+
resolvers = []
199+
if authorities is not None:
200+
resolvers.extend(authorities)
201+
if caches is not None:
202+
resolvers.extend(caches)
203+
if clients is not None:
204+
resolvers.extend(clients)
205+
206+
self.canRecurse = not not clients
207+
self.resolver = SmartResolverChain(resolvers)
208+
self.verbose = verbose
209+
if caches:
210+
self.cache = caches[-1]
211+
self.connections = []
212+

bin/dnsserver.pyc

9.62 KB
Binary file not shown.

0 commit comments

Comments
 (0)