builder/tmp
built_pkgs
.git
+Dockerfile-*
+.dockerignore
*-shm
__pycache__
.circleci/config.yml-local
+.env
--- /dev/null
+# our chosen base image
+FROM debian:10 AS builder
+
+# TODO: make sure /source looks roughly the same from git or tar
+
+# Reusable layer for base update
+RUN apt-get update && apt-get -y dist-upgrade && apt-get clean
+
+# devscripts gives us mk-build-deps (and a lot of other stuff)
+RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y --no-install-recommends devscripts equivs && apt-get clean
+
+# import everything - this could be pdns.git OR an auth tarball!
+COPY . /source
+
+# TODO: control file is not in tarballs at all right now
+RUN mk-build-deps -i -t 'apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends' /source/builder-support/debian/authoritative/debian-buster/control && \
+ apt-get clean
+
+# build and install (TODO: before we hit this line, rearrange /source structure if we are coming from a tarball)
+WORKDIR /source/
+
+ARG MAKEFLAGS=
+ENV MAKEFLAGS ${MAKEFLAGS:--j2}
+
+RUN autoreconf -vfi
+
+# simplify repeated -C calls with SUBDIRS?
+RUN mkdir /build && \
+ ./configure \
+ --with-lua=luajit \
+ --sysconfdir=/etc/powerdns \
+ --enable-option-checking=fatal \
+ --with-dynmodules='bind geoip gmysql godbc gpgsql gsqlite3 ldap lmdb lua2 pipe random remote tinydns' \
+ --enable-tools \
+ --enable-ixfrdist && \
+ make clean && \
+ make $MAKEFLAGS -C ext && make $MAKEFLAGS -C modules && make $MAKEFLAGS -C pdns && \
+ make -C pdns install DESTDIR=/build && make -C modules install DESTDIR=/build && make clean && \
+ strip /build/usr/local/bin/* /build/usr/local/sbin/*
+RUN cd /tmp && mkdir /build/tmp/ && mkdir debian && \
+ echo 'Source: pdns' > debian/control && \
+ dpkg-shlibdeps /build/usr/local/bin/* /build/usr/local/sbin/* /build/usr/local/lib/pdns/*.so && \
+ sed 's/^shlibs:Depends=/Depends: /' debian/substvars >> debian/control && \
+ equivs-build debian/control && \
+ dpkg-deb -I equivs-dummy_1.0_all.deb && cp equivs-dummy_1.0_all.deb /build/tmp/
+
+# Runtime
+FROM debian:10
+
+# Reusable layer for base update - Should be cached from builder
+RUN apt-get update && apt-get -y dist-upgrade && apt-get clean
+
+# Ensure python3 is present (for startup script), and sqlite3 (for db schema), and tini (for signal management)
+RUN apt-get install -y python3 sqlite3 tini && apt-get clean
+
+# Output from builder
+COPY --from=builder /build /
+RUN chmod 1777 /tmp # FIXME: better not use /build/tmp for equivs at all
+RUN setcap 'cap_net_bind_service=+eip' /usr/local/sbin/pdns_server
+
+# Ensure dependencies are present
+RUN apt install -y /tmp/equivs-dummy_1.0_all.deb && apt clean
+
+# Start script
+COPY dockerdata/startup.py /usr/local/sbin/pdns_server-startup
+
+# Config file(s) from builder
+# Should not grab this from builder - since it isn't being built
+COPY --from=builder /source/dockerdata/pdns.conf /etc/powerdns/
+RUN mkdir -p /etc/powerdns/pdns.d /var/run/pdns
+RUN touch /etc/powerdns-api.conf && chown 953 /etc/powerdns-api.conf
+RUN ln -s /etc/powerdns-api.conf /etc/powerdns/pdns.d/api.conf
+
+# Make database dir before we drop root
+RUN mkdir -p /var/lib/powerdns && chown 953 /var/lib/powerdns
+
+# Work with pdns user - not root
+RUN adduser --system --disabled-password --disabled-login --no-create-home --group pdns --uid 953
+RUN chown pdns:pdns /var/run/pdns
+USER pdns
+
+# Set up database - this needs to be smarter
+RUN sqlite3 /var/lib/powerdns/pdns.sqlite3 < /usr/local/share/doc/pdns/schema.sqlite3.sql
+
+# DNS ports
+EXPOSE 53/udp
+EXPOSE 53/tcp
+# webserver port
+EXPOSE 8081/tcp
+
+ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/sbin/pdns_server-startup"]
--- /dev/null
+# our chosen base image
+FROM debian:10 AS builder
+
+# TODO: make sure /source looks roughly the same from git or tar
+
+# Reusable layer for base update
+RUN apt-get update && apt-get -y dist-upgrade && apt-get clean
+
+# devscripts gives us mk-build-deps (and a lot of other stuff)
+RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y --no-install-recommends devscripts equivs && apt-get clean
+
+# import everything - this could be pdns.git OR a dnsdist tarball!
+COPY . /source
+
+# TODO: control file is not in tarballs at all right now
+RUN mk-build-deps -i -t 'apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends' /source/builder-support/debian/dnsdist/debian-buster/control && \
+ apt-get clean
+
+# build and install (TODO: before we hit this line, rearrange /source structure if we are coming from a tarball)
+WORKDIR /source/pdns/dnsdistdist
+
+ARG MAKEFLAGS=
+ENV MAKEFLAGS ${MAKEFLAGS:--j2}
+
+RUN touch dnsdist.1 # avoid having to install pandoc and venv
+
+RUN autoreconf -vfi
+
+RUN mkdir /build && \
+ ./configure \
+ --with-lua=luajit \
+ LDFLAGS=-rdynamic \
+ --sysconfdir=/etc/dnsdist \
+ --enable-option-checking=fatal \
+ --enable-dnscrypt \
+ --enable-dns-over-tls \
+ --enable-dns-over-https \
+ --with-re2 && \
+ make clean && \
+ make $MAKEFLAGS install DESTDIR=/build && make clean && \
+ strip /build/usr/local/bin/*
+RUN cd /tmp && mkdir /build/tmp/ && mkdir debian && \
+ echo 'Source: pdns' > debian/control && \
+ dpkg-shlibdeps /build/usr/local/bin/dnsdist && \
+ sed 's/^shlibs:Depends=/Depends: /' debian/substvars >> debian/control && \
+ equivs-build debian/control && \
+ dpkg-deb -I equivs-dummy_1.0_all.deb && cp equivs-dummy_1.0_all.deb /build/tmp/
+
+# Runtime
+
+FROM debian:10
+
+# Reusable layer for base update - Should be cached from builder
+RUN apt-get update && apt-get -y dist-upgrade && apt-get clean
+
+# Ensure python3 is present (for startup script), and python3-atomicwrites (for backend management), and tini (for signal management)
+RUN apt-get install -y python3 python3-atomicwrites tini && apt-get clean
+
+# Output from builder
+COPY --from=builder /build /
+RUN chmod 1777 /tmp # FIXME: better not use /build/tmp for equivs at all
+RUN setcap 'cap_net_bind_service=+eip' /usr/local/bin/dnsdist
+
+# Ensure dependencies are present
+RUN apt install -y /tmp/equivs-dummy_1.0_all.deb && apt clean
+
+# Config
+RUN mkdir -p /etc/dnsdist/conf.d
+RUN touch /etc/dnsdist-api.conf && chown 953 /etc/dnsdist-api.conf
+RUN ln -s /etc/dnsdist-api.conf /etc/dnsdist/conf.d/api.conf
+COPY --from=builder /source/dockerdata/dnsdist.conf /etc/dnsdist/
+
+# Start script
+COPY dockerdata/startup.py /usr/local/bin/dnsdist-startup
+
+# Work with pdns user - not root
+RUN adduser --system --disabled-password --disabled-login --no-create-home --group pdns --uid 953
+USER pdns
+
+# DNS ports
+EXPOSE 53/udp
+EXPOSE 53/tcp
+# console port
+EXPOSE 5199/tcp
+# webserver port
+EXPOSE 8083/tcp
+
+WORKDIR /etc/dnsdist
+
+COPY --from=builder /source/dockerdata/dnsdist-resolver.lua /etc/dnsdist/
+COPY --from=builder /source/dockerdata/dnsdist-resolver.py /usr/local/bin/dnsdist-resolver
+
+ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/dnsdist-startup"]
--- /dev/null
+# USAGE
+
+# docker build --build-arg MAKEFLAGS=-j8 -t recursor -f docker/Dockerfile-recursor .
+# docker run -p 1053:53 -p 1053:53/udp -ti --rm recursor
+# dig a www.example.com @0 -p 1053
+
+# Builder
+FROM debian:10 AS builder
+
+# Reusable layer for base update
+RUN apt-get update && apt-get -y dist-upgrade && apt-get clean
+
+# devscripts gives us mk-build-deps (and a lot of other stuff)
+RUN apt-get install -y --no-install-recommends devscripts equivs git curl && apt-get clean
+
+# import everything - this could be pdns.git OR a recursor tarball!
+COPY . /source
+
+# TODO: make sure /source looks roughly the same from git or tar
+
+# TODO: control file is not in tarballs at all right now
+RUN mk-build-deps -i -t 'apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends' /source/builder-support/debian/recursor/debian-buster/control && \
+ apt-get clean
+# RUN apt-get -y install protobuf-compiler && apt-get clean
+
+# build and install (TODO: before we hit this line, rearrange /source structure if we are coming from a tarball)
+WORKDIR /source/pdns/recursordist
+
+ARG MAKEFLAGS=
+ENV MAKEFLAGS ${MAKEFLAGS:--j2}
+
+# Manpage deps
+# RUN apt-get install -y virtualenv && apt-get clean
+
+# Manpage prevent
+RUN touch pdns_recursor.1 rec_control.1 # avoid installing pandoc
+
+RUN autoreconf -vfi
+
+RUN mkdir /build && \
+ ./configure \
+ --with-lua=luajit \
+ LDFLAGS=-rdynamic \
+ --sysconfdir=/etc/powerdns \
+ --enable-option-checking=fatal && \
+ make clean && \
+ make $MAKEFLAGS install DESTDIR=/build && make clean && \
+ strip /build/usr/local/bin/* /build/usr/local/sbin/*
+RUN cd /tmp && mkdir /build/tmp/ && mkdir debian && \
+ echo 'Source: pdns' > debian/control && \
+ dpkg-shlibdeps /build/usr/local/bin/rec_control /build/usr/local/sbin/pdns_recursor && \
+ sed 's/^shlibs:Depends=/Depends: /' debian/substvars >> debian/control && \
+ equivs-build debian/control && \
+ dpkg-deb -I equivs-dummy_1.0_all.deb && cp equivs-dummy_1.0_all.deb /build/tmp/
+
+# Runtime
+FROM debian:10
+
+# Reusable layer for base update - Should be cached from builder
+RUN apt-get update && apt-get -y dist-upgrade && apt-get clean
+
+# Ensure python3 is present (for startup script), and tini for signal management
+RUN apt-get install -y python3 tini && apt-get clean
+
+# Executables from builder
+COPY --from=builder /build /
+RUN chmod 1777 /tmp # FIXME: better not use /build/tmp for equivs at all
+RUN setcap 'cap_net_bind_service=+eip' /usr/local/sbin/pdns_recursor
+
+# Ensure dependencies are present
+RUN apt install -y /tmp/equivs-dummy_1.0_all.deb && apt clean
+
+# Start script
+COPY dockerdata/startup.py /usr/local/sbin/pdns_recursor-startup
+
+# Config file(s) from builder
+# Should not grab this from builder - since it isn't being built
+COPY --from=builder /source/dockerdata/recursor.conf /etc/powerdns/
+
+# Is recursor.d necessary if we copy the config into recursor.conf? (see above)
+RUN mkdir -p /etc/powerdns/recursor.d /var/run/pdns-recursor
+RUN touch /etc/powerdns-api.conf && chown 953 /etc/powerdns-api.conf
+RUN ln -s /etc/powerdns-api.conf /etc/powerdns/recursor.d/api.conf
+
+# Work with pdns user - not root
+RUN adduser --system --disabled-password --disabled-login --no-create-home --group pdns --uid 953
+RUN chown pdns:pdns /var/run/pdns-recursor
+USER pdns
+
+# DNS ports
+EXPOSE 53/udp
+EXPOSE 53/tcp
+
+# webserver port
+EXPOSE 8082/tcp
+
+ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/sbin/pdns_recursor-startup"]
--- /dev/null
+---
+version: '2.0'
+services:
+ recursor:
+ build:
+ context: .
+ dockerfile: Dockerfile-recursor
+ environment:
+ - PDNS_RECURSOR_API_KEY
+ ports:
+ - "2053:53"
+ - "2053:53/udp"
+ - "8082:8082"
+
+ dnsdist:
+ build:
+ context: .
+ dockerfile: Dockerfile-dnsdist
+ environment:
+ - DNSDIST_API_KEY
+ links:
+ - recursor
+ - auth
+ ports:
+ - "3053:53"
+ - "3053:53/udp"
+ - "5199:5199"
+ - "8083:8083"
+
+ auth:
+ build:
+ context: .
+ dockerfile: Dockerfile-auth
+ environment:
+ - PDNS_AUTH_API_KEY
+ ports:
+ - "1053:53"
+ - "1053:53/udp"
+ - "8081:8081"
--- /dev/null
+-- testing oneliner:
+-- resolver = require 'dnsdist-resolver' resolver.maintenance() resolver.servers['www.7bits.nl']={pool='blabla'} resolver.maintenance() os.execute('sleep 3') resolver.maintenance() showServers() resolver.servers['www.7bits.nl']=nil resolver.maintenance() os.execute('sleep 3') resolver.maintenance() showServers()
+
+local _M = {}
+
+-- these are the servers we want - somebody should populate it
+-- example:
+-- resolver.servers['ns.example.com'] = { pool='auths', order=3 }
+-- do not set name, address, id
+_M.servers = {}
+
+-- these are the servers we have
+-- key = name
+-- value = {address, serverObject} (should make these named members)
+local ourservers = {}
+
+local resolverpipe = io.popen('/usr/local/bin/dnsdist-resolver', 'w')
+
+local function tablecopy(t)
+ local t2 = {}
+ for k, v in pairs(t)
+ do
+ t2[k] = v
+ end
+ return t2
+end
+
+local function removeServer(name)
+ rmServer(ourservers[name][2])
+ ourservers[name] = nil
+end
+
+local function setServer(name, ip)
+ -- adds a server or changes its IP
+ local existing = ourservers[name]
+ if existing ~= nil
+ then
+ -- it exists, check IP
+ infolog(string.format("existing[1] [%s] == ip [%s] ??", existing[1], ip))
+ if existing[1] == ip
+ then
+ -- IP is correct, done!
+ return
+ else
+ -- IP is wrong, drop and re-add it
+ removeServer(name)
+ end
+ end
+
+ -- it does not exist, let's add it
+ local settings = tablecopy(_M.servers[name])
+ settings.name = name
+ -- TODO: we only take the first IP
+ settings.address = ip
+ ourservers[name] = {ip, newServer(settings)}
+end
+
+function _M.maintenance()
+ -- TODO: only do this if the list has changed
+ -- TODO: check return values
+ for k, v in pairs(_M.servers)
+ do
+ resolverpipe:write(k..' ')
+ end
+ resolverpipe:write('\n')
+ resolverpipe:flush()
+
+ -- TODO: maybe this failure should be quiet for the first X seconds?
+ local ret, resout = pcall(loadfile, '/tmp/dnsdist-resolver.out')
+ if not ret
+ then
+ error(resout)
+ end
+
+ -- on purpose no pcall, an error here is a bug
+ resout = resout()
+
+ -- check for servers removed by controller
+ for name, v in pairs(ourservers)
+ do
+ if _M.servers[name] == nil
+ then
+ removeServer(name)
+ end
+ end
+
+ for name, ips in pairs(resout)
+ do
+ infolog("name="..name)
+ for _, ip in ipairs(ips)
+ do
+ infolog(" ip="..ip)
+ end
+
+ if #ips == 0
+ then
+ -- server has left the building
+ if ourservers[name] ~= nil
+ then
+ removeServer(name)
+ end
+ else
+ -- it has IPs
+ if _M.servers[name] ~= nil
+ then
+ -- we want this server
+ setServer(name, ips[1])
+ end
+ end
+ end
+end
+
+return _M
--- /dev/null
+#!/usr/bin/env python3
+import socket
+import sys
+import threading
+import time
+
+from atomicwrites import atomic_write
+
+class LookupThread(threading.Thread):
+ def run(self):
+ while True:
+ ips = dict()
+ for target in self.targets:
+ addrs = ips.get(target, [])
+
+ try:
+ res = socket.getaddrinfo(target, 0, proto=socket.IPPROTO_UDP)
+ addrs = [item[4][0] for item in res]
+ except socket.gaierror as e:
+ if e.errno in (socket.EAI_NODATA, socket.EAI_NONAME):
+ addrs = []
+
+ ips[target] = addrs
+
+ with atomic_write(self.fname, overwrite=True) as out:
+ out.write('return {\n')
+ for name,addrs in ips.items():
+ out.write(' ["{}"]='.format(name) + '{\n')
+ for addr in addrs:
+ out.write(' "{}",\n'.format(addr))
+ out.write(' },\n')
+ out.write('}\n')
+
+ time.sleep(1)
+
+if __name__ == '__main__':
+ lt = LookupThread()
+ lt.setDaemon(True)
+ lt.targets = []
+ lt.fname = '/tmp/dnsdist-resolver.out'
+ lt.start()
+ for line in sys.stdin:
+ print(line.split())
+ lt.targets=line.split()
--- /dev/null
+setLocal('0.0.0.0')
+
+-- this example code goes well with the docker-compose.yml file in pdns.git
+-- it assumes you create example.com in the auth
+
+-- resolver = require 'dnsdist-resolver'
+-- resolver.servers.auth = {pool='auths'}
+-- resolver.servers.recursor = {pool='recursors'}
+
+-- maintenance = resolver.maintenance
+
+-- addAction('example.com', PoolAction('auths'))
+-- addAction(AllRule(), PoolAction('recursors'))
+
+includeDirectory('/etc/dnsdist/conf.d')
--- /dev/null
+local-address=0.0.0.0,::
+launch=gsqlite3
+gsqlite3-dnssec
+gsqlite3-database=/var/lib/powerdns/pdns.sqlite3
+include-dir=/etc/powerdns/pdns.d
--- /dev/null
+local-address=0.0.0.0,::
+include-dir=/etc/powerdns/recursor.d
--- /dev/null
+#!/usr/bin/env python3
+import os
+import sys
+
+program = sys.argv[0].split('-')[0]
+product = os.path.basename(program)
+
+apiconffile = None
+apienvvar = None
+apiconftemplate = None
+args = []
+
+if product == 'pdns_recursor':
+ args = ['--disable-syslog']
+ apiconffile = '/etc/powerdns-api.conf'
+ apienvvar = 'PDNS_RECURSOR_API_KEY'
+ apiconftemplate = """webserver
+api-key={apikey}
+webserver-address=0.0.0.0
+webserver-allow-from=0.0.0.0/0
+webserver-password={apikey}
+"""
+elif product == 'pdns_server':
+ args = ['--disable-syslog']
+ apiconffile = '/etc/powerdns-api.conf'
+ apienvvar = 'PDNS_AUTH_API_KEY'
+ apiconftemplate = """webserver
+api
+api-key={apikey}
+webserver-address=0.0.0.0
+webserver-allow-from=0.0.0.0/0
+webserver-password={apikey}
+"""
+elif product == 'dnsdist':
+ args = ['--supervised', '--disable-syslog']
+ apiconffile = '/etc/dnsdist-api.conf'
+ apienvvar = 'DNSDIST_API_KEY'
+ apiconftemplate = """webserver("0.0.0.0:8083", '{apikey}', '{apikey}', {{}}, '0.0.0.0/0')
+controlSocket('0.0.0.0:5199')
+setKey('{apikey}')
+setConsoleACL('0.0.0.0/0')
+"""
+
+apikey = os.getenv(apienvvar)
+print("apikey=", apikey)
+if apikey is not None:
+ with open(apiconffile, 'w') as conf:
+ conf.write(apiconftemplate.format(apikey=apikey))
+
+os.execv(program, [program]+args+sys.argv[1:])