[Pdns-users] Attempting to use single pipe-backend process
Chris Foote
chris at inetd.com.au
Fri Oct 20 12:14:43 UTC 2006
I have a problem with getting PowerDNS to only use a single instance
of a pipe-backend process - it always runs a second copy after PowerDNS
gets its first DNS query:
enum1:/etc/powerdns/pdns.d# invoke-rc.d pdns monitor
Oct 20 21:58:52 [PIPEBackend] This is the pipebackend version 2.9.20 (Sep 9 2006, 17:27:05) reporting
Oct 20 21:58:52 This is a standalone pdns
Oct 20 21:58:52 It is advised to bind to explicit addresses with the --local-address option
Oct 20 21:58:52 UDP server bound to 0.0.0.0:53
Oct 20 21:58:52 PowerDNS 2.9.20 (C) 2001-2006 PowerDNS.COM BV (Sep 9 2006, 17:34:31, gcc 3.3.5 (Debian 1:3.3.5-13)) starting up
Oct 20 21:58:52 PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2.
Oct 20 21:58:52 Set effective group id to 106
Oct 20 21:58:52 Set effective user id to 104
Oct 20 21:58:52 About to create 1 backend threads for UDP
% Oct 20 21:58:52 Backend launched with banner: OK Python backend firing up
Oct 20 21:58:53 Done launching threads, ready to distribute questions
************[ DNS query performed here, which is when the 2nd process starts up ]
Oct 20 22:00:15 Engaging bypass - now operating unthreaded
Oct 20 22:00:15 Backend launched with banner: OK Python backend firing up
Oct 20 22:00:15 Query: 'Q www.example.com IN ANY -1 127.0.0.1'
Oct 20 22:00:15 Query: 'Q webserver.example.com IN ANY -1 127.0.0.1'
I can confirm that the first backend process (Python script attached)
never sees the query, and pdns sends the query to the second process
after starting it up (why ?...)
I upgraded to powerdns 2.9.20 from 2.9.17 hoping that the recent patch
to the CoProcess code[1] might have fixed it, but not for my case.
The config I'm using is:
allow-recursion=127.0.0.3
config-dir=/etc/powerdns
daemon=yes
disable-axfr=yes
guardian=yes
lazy-recursion=yes
local-address=0.0.0.0
local-port=53
module-dir=/usr/lib/powerdns
setgid=pdns
setuid=pdns
socket-dir=/var/run
version-string=powerdns
include=/etc/powerdns/pdns.d
cache-ttl=0
disable-tcp=yes
distributor-threads=1
launch=pipe
logfile=/var/log/pdns.log
loglevel=9
negquery-cache-ttl=0
query-cache-ttl=0
use-logfile=yes
query-logging=yes
pipe-command=/tmp/dummy-backend.py
Does anyone have a hint for allowing just a single process to run ?
Best regards,
Chris
[1] http://wiki.powerdns.com/projects/trac/changeset/525
-------------- next part --------------
#!/usr/bin/python2.4
"""Test Python process for PowerDNS pipe backend."""
import sys, os, time
class DNSLookup(object):
"""Handle PowerDNS pipe-backend domain name lookups."""
ttl = 1
def __init__(self, query):
"""parse DNS query and produce lookup result.
query: a sequence containing the DNS query as per PowerDNS manual appendix A:
http://downloads.powerdns.com/documentation/html/backends-detail.html#PIPEBACKEND-PROTOCOL
"""
(_type, qname, qclass, qtype, _id, ip) = query
self.has_result = False # has a DNS query response
qname_lower = qname.lower()
self.results = []
if (qtype == 'A' or qtype == 'ANY') and qname_lower == 'webserver.example.com':
self.results.append('DATA\t%s\t%s\tA\t%d\t-1\t1.2.3.4' %
(qname, qclass, DNSLookup.ttl))
self.results.append('DATA\t%s\t%s\tA\t%d\t-1\t1.2.3.5' %
(qname, qclass, DNSLookup.ttl))
self.results.append('DATA\t%s\t%s\tA\t%d\t-1\t1.2.3.6' %
(qname, qclass, DNSLookup.ttl))
self.has_result = True
elif (qtype == 'CNAME' or qtype == 'ANY') and qname_lower == 'www.example.com':
self.results.append('DATA\t%s\t%s\tCNAME\t%d\t-1\twebserver.example.com' %
(qname, qclass, DNSLookup.ttl))
self.has_result = True
def str_result(self):
"""return string result suitable for pipe-backend output to PowerDNS."""
if self.has_result:
return '\n'.join(self.results)
else:
return ''
class Logger(object):
def __init__(self):
pid = os.getpid()
self.logfile = '/tmp/backend-%d.log' % pid
def write(self, msg):
logline = '%s|%s\n' % (time.asctime(), msg)
f = file(self.logfile, 'a')
f.write(logline)
f.close()
def debug_log(msg):
logger.write(msg)
class PowerDNSbackend(object):
"""The main PowerDNS pipe backend process."""
def __init__(self, filein, fileout):
"""initialise and run PowerDNS pipe backend process."""
self.filein = filein
self.fileout = fileout
self._process_requests() # main program loop
def _process_requests(self):
"""THE main program loop."""
first_time = True
while 1:
rawline = self.filein.readline()
if rawline == '':
debug_log('EOF')
return # EOF detected
line = rawline.rstrip()
debug_log('received from pdns:%s' % line)
if first_time:
if line == 'HELO\t1':
self._fprint('OK\tPython backend firing up')
else:
self._fprint('FAIL')
debug_log('HELO input not received - execution aborted')
rawline = self.filein.readline() # as per docs - read another line before aborting
debug_log('calling sys.exit()')
sys.exit(1)
first_time = False
else:
query = line.split('\t')
if len(query) != 6:
self._fprint('LOG\tPowerDNS sent unparseable line')
self._fprint('FAIL')
else:
debug_log('Performing DNSLookup(%s)' % repr(query))
lookup = DNSLookup(query)
if lookup.has_result:
self._fprint(lookup.str_result())
self._fprint('END')
def _fprint(self, message):
"""Print the given message with newline and flushing."""
self.fileout.write(message + '\n')
self.fileout.flush()
debug_log('sent to pdns:%s' % message)
if __name__ == '__main__':
logger = Logger()
infile = sys.stdin
#sys.stdout.close()
#outfile = os.fdopen(1, 'w', 1)
outfile = sys.stdout
try:
PowerDNSbackend(infile, outfile)
except:
debug_log('execution failure:' + str(sys.exc_info()[0]))
raise
More information about the Pdns-users
mailing list