]> gitweb.michael.orlitzky.com - mjo-overlay.git/commitdiff
Add rbldnsd in preparation for fixing two bugs.
authorMichael Orlitzky <michael@orlitzky.com>
Sat, 7 Dec 2013 08:49:37 +0000 (03:49 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Sat, 7 Dec 2013 08:49:37 +0000 (03:49 -0500)
net-dns/rbldnsd/Manifest [new file with mode: 0644]
net-dns/rbldnsd/files/confd-0.997a [new file with mode: 0644]
net-dns/rbldnsd/files/initd-0.997a [new file with mode: 0644]
net-dns/rbldnsd/files/rbldnsd-0.997a-robust-ipv6-test-support.patch [new file with mode: 0644]
net-dns/rbldnsd/metadata.xml [new file with mode: 0644]
net-dns/rbldnsd/rbldnsd-0.997a.ebuild [new file with mode: 0644]

diff --git a/net-dns/rbldnsd/Manifest b/net-dns/rbldnsd/Manifest
new file mode 100644 (file)
index 0000000..16c4bfa
--- /dev/null
@@ -0,0 +1,6 @@
+AUX confd-0.997a 1003 SHA256 32ce431bafc75203b2a6d4e7b0ea19a7bbbcfeb9ef03983cdc9fff027b915d65 SHA512 b7560453c82467a5b0ea0a1f3644f57ec745246d2f689beb77f2498ae962fd80257413c1eede4d62552f7ce402fe43ac6a5ed5906a54ca06a315205e116c3324 WHIRLPOOL 26ff5468d9d296b9726c933375c5cccda6446dd5c9fe239de5e9b4c0439776fb30bec3903919b28dd321763af302d6572c43463c9cf98ba47744fd587a166248
+AUX initd-0.997a 677 SHA256 41effc1aea5838042a626a24f8926b413c51224e9f2af8377bbf1b2e32f0135a SHA512 530c273ea1267fe39c6a3180fa8088bd05a2c52d4ec72c25a3652306a69b3f421afde5f981a9968f998861f8543dbb9ac840227111d5813911ccf862ea33275f WHIRLPOOL 7814524f76c90ae50a079bf0a3d31f797672acc8601005f41fe783dcb33947485b7295fd8e060d0c4c2ead1315b05c2abcc32207d3669849ffe6bb3cda15b278
+AUX rbldnsd-0.997a-robust-ipv6-test-support.patch 10866 SHA256 a1e29bc52a2d69c73c50300628aba0187556491246c54fbd6bb518e231f0bf89 SHA512 37f47f5305c074a8d1267f0879fe96a311589321a11db61ac27f5cc9db246f126811cc86343a4535a14487a52dc30312c70783470a154e8e750f276098d3e5a8 WHIRLPOOL e2366b5064768b105980d4c8f8572d93b7a24b45f8fddd9ec34944017fc5de3037c6808ffeeb40b6107751ebb617b8dc22aaff36363dbfd6010b207be8b352b4
+DIST rbldnsd-0.997a.tar.gz 144771 SHA256 9c17c6bde6995058204a66805444039d31523a7d4ef40cec059e505a0882a8ef SHA512 9a3e1a0ad2cd9dd08bcc114c70213a875e984f3761fa32c44fe544d8173f54330fe355ad229a120e64b8f4c8286187d0baa055526d3a85bc846df070bb213529 WHIRLPOOL b453396c9876fd4972c6028b5916ae9717d60d555e5bb33bc97f0a8910ee516a80d1a3cb6030a3850ec304794f4a00fd9f3dced0d5c7fd1388e7d87d53fedb24
+EBUILD rbldnsd-0.997a.ebuild 1563 SHA256 585a0c3c316ece2aeb355863ec91388a36b9247a3dfa76519bc97540c33a4ca0 SHA512 745593f57c48035731ae6e70ce9aefb7c8cd3def3c697287c6aae38f8d80882fdf7a099ad410d574d188b6ffadc394a3dd4f5b6cd42e5ff0f03fee0fd09a5780 WHIRLPOOL 69ca8650ca08073d77d375926a4aa00926403b86efe6bad617816b51182410556481c79b8538ed7c030b8a8f16824278c03e591b8edee7e61c811472655b44b2
+MISC metadata.xml 1179 SHA256 6a9d5a1772e174859bf13dbe53a955671ad97eeb8322dd6ff9772046460e017d SHA512 d2f2925bd8de92dc0d9dffce03b0ce8a61c28a0abbbdc3ca21ca10ac3f22a773dcbf19e880563e0557a1512fe3e0586f3b4ef5abd0b6add8278e6b24ea709051 WHIRLPOOL 42f38dbd07679c6e1ceb9d3b054928e5a0f3befdb8d4f5e74b3b23a486bb98066bc7a44e2dab05ef39465f44e41ad815a0cc3f7a32add5bff84c78a484a986c6
diff --git a/net-dns/rbldnsd/files/confd-0.997a b/net-dns/rbldnsd/files/confd-0.997a
new file mode 100644 (file)
index 0000000..afe0cff
--- /dev/null
@@ -0,0 +1,22 @@
+# A whitespace-separated list of addresses on which to listen. The
+# syntax is "host:port", where the port defaults to 53.
+LISTEN="127.0.0.1
+        192.168.0.1"
+
+# A whitespace-separated list of RBL zones. For the correct syntax, please
+# see the rbldnsd(8) man page. The following $ZONES will look for
+# files named "badguys.example.com" and "spammers.example.net" (in the
+# appropriate format) under /var/db/rbldnsd, and use those same names
+# for the blacklists contained therein.
+ZONES="badguys.example.com:ip4set:badguys.example.com
+       spammers.example.net:ip4tset:spammers.example.net"
+
+# Add any additional options for the rbldnsd daemon below. The -a and
+# -vv below are suggested for performance/security reasons. They are
+# described in the man page.
+#
+# The rootdir (-r) and PID (-p) options are passed automatically, with
+# rootdir set to /var/db/rbldnsd (where you should put your zone
+# files). The daemon will run as the rbldns user, which was created by
+# portage.
+OPTIONS="-a -vv"
diff --git a/net-dns/rbldnsd/files/initd-0.997a b/net-dns/rbldnsd/files/initd-0.997a
new file mode 100644 (file)
index 0000000..6e830b3
--- /dev/null
@@ -0,0 +1,29 @@
+#!/sbin/runscript
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/net-dns/rbldnsd/files/initd-0.997,v 1.1 2013/07/08 17:08:52 xmw Exp $
+
+depend() {
+    need net
+}
+
+start() {
+    ebegin "Starting rbldnsd"
+
+    start-stop-daemon --start --quiet --pidfile /run/rbldnsd.pid \
+       --exec /usr/sbin/rbldnsd -- \
+       -r /var/db/rbldnsd \
+       -p /run/rbldnsd.pid \
+       $(for x in ${LISTEN}; do echo "-b ${x}"; done) \
+       ${OPTIONS} \
+       ${ZONES}
+
+    eend $?
+}
+
+stop() {
+    ebegin "Stopping rbldnsd"
+    start-stop-daemon --stop --quiet --pidfile /run/rbldnsd.pid \
+       --exec /usr/sbin/rbldnsd
+    eend $?
+}
diff --git a/net-dns/rbldnsd/files/rbldnsd-0.997a-robust-ipv6-test-support.patch b/net-dns/rbldnsd/files/rbldnsd-0.997a-robust-ipv6-test-support.patch
new file mode 100644 (file)
index 0000000..5621075
--- /dev/null
@@ -0,0 +1,329 @@
+diff --git a/NEWS b/NEWS
+index 8d8bdd9..4d8c01d 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,19 @@
+ This file describes user-visible changes in rbldnsd.
+ Newer news is at the top.
++Next release
++
++ - fix tests for systems without ipv6 support, or when ipv6 is
++   disabled in rbldnsd at compile-time
++
++ - fix tests for API change in pydns >= 2.3.6
++
++ - It is no longer an error to request binding to a particular
++   address/port more than once. (The subsequent requests are simply
++   ignored.) (This avoids confusion on certain systems/configurations
++   where gethostbyname("localhost") can return 127.0.0.1 multiple
++   times.)
++
+ 0.997a (23 Jul 2013)
+  - minor fixes/changes in packaging, no code changes.
+diff --git a/rbldnsd.c b/rbldnsd.c
+index abf1d01..8322bdd 100644
+--- a/rbldnsd.c
++++ b/rbldnsd.c
+@@ -203,10 +203,79 @@ static volatile int signalled;
+ #define SIGNALLED_ZSTATS      0x10
+ #define SIGNALLED_TERM                0x20
++static inline int sockaddr_in_equal(const struct sockaddr_in *addr1,
++                                    const struct sockaddr_in *addr2)
++{
++  return (addr1->sin_port == addr2->sin_port
++          && addr1->sin_addr.s_addr == addr2->sin_addr.s_addr);
++}
++
++#ifndef NO_IPv6
++static inline int sockaddr_in6_equal(const struct sockaddr_in6 *addr1,
++                                     const struct sockaddr_in6 *addr2)
++{
++  if (memcmp(addr1->sin6_addr.s6_addr, addr2->sin6_addr.s6_addr, 16) != 0)
++    return 0;
++  return (addr1->sin6_port == addr2->sin6_port
++          && addr1->sin6_flowinfo == addr2->sin6_flowinfo
++          && addr1->sin6_scope_id == addr2->sin6_scope_id);
++}
++#endif
++
++static inline int sockaddr_equal(const struct sockaddr *addr1,
++                                 const struct sockaddr *addr2)
++{
++  if (addr1->sa_family != addr2->sa_family)
++    return 0;
++  switch (addr1->sa_family) {
++  case AF_INET:
++    return sockaddr_in_equal((const struct sockaddr_in *)addr1,
++                             (const struct sockaddr_in *)addr2);
++#ifndef NO_IPv6
++    return sockaddr_in6_equal((const struct sockaddr_in6 *)addr1,
++                              (const struct sockaddr_in6 *)addr2);
++#endif
++    default:
++      error(0, "unknown address family (%d)", addr1->sa_family);
++  }
++}
++
++/* already_bound(addr, addrlen)
++ *
++ * Determine whether we've already bound to a particular address.
++ * This is here mostly to deal with the fact that on certain systems,
++ * gethostbyname()/getaddrinfo() can return a duplicate 127.0.0.1
++ * for 'localhost'.  See
++ *   - http://sourceware.org/bugzilla/show_bug.cgi?id=4980
++ *   - https://bugzilla.redhat.com/show_bug.cgi?id=496300
++ */
++static int already_bound(const struct sockaddr *addr, socklen_t addrlen) {
++#ifdef NO_IPv6
++  struct sockaddr_in addr_buf;
++#else
++  struct sockaddr_in6 addr_buf;
++#endif
++  struct sockaddr *boundaddr = (struct sockaddr *)&addr_buf;
++  socklen_t buflen;
++  int i;
++
++  for (i = 0; i < numsock; i++) {
++    buflen = sizeof(addr_buf);
++    if (getsockname(sock[i], boundaddr, &buflen) < 0)
++      error(errno, "getsockname failed");
++    if (buflen == addrlen && sockaddr_equal(boundaddr, addr))
++      return 1;
++  }
++  return 0;
++}
++
+ #ifdef NO_IPv6
+ static void newsocket(struct sockaddr_in *sin) {
+   int fd;
+   const char *host = ip4atos(ntohl(sin->sin_addr.s_addr));
++
++  if (already_bound((struct sockaddr *)sin, sizeof(*sin)))
++    return;
+   if (numsock >= MAXSOCK)
+     error(0, "too many listening sockets (%d max)", MAXSOCK);
+   fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+@@ -223,6 +292,8 @@ static int newsocket(struct addrinfo *ai) {
+   int fd;
+   char host[NI_MAXHOST], serv[NI_MAXSERV];
++  if (already_bound(ai->ai_addr, ai->ai_addrlen))
++    return 1;
+   if (numsock >= MAXSOCK)
+     error(0, "too many listening sockets (%d max)", MAXSOCK);
+   fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+diff --git a/rbldnsd.py b/rbldnsd.py
+index 9300ef2..4b78dee 100644
+--- a/rbldnsd.py
++++ b/rbldnsd.py
+@@ -2,6 +2,7 @@
+ """
++import errno
+ from itertools import count
+ import subprocess
+ from tempfile import NamedTemporaryFile, TemporaryFile
+@@ -12,6 +13,14 @@ try:
+     import DNS
+ except ImportError:
+     raise RuntimeError("The pydns library is not installed")
++try:
++    from DNS import SocketError as DNS_SocketError
++except ImportError:
++    class DNS_SocketError(Exception):
++        """ Dummy, never raised.
++
++        (Older versions of pydns before 2.3.6 do not raise SocketError.)
++        """
+ DUMMY_ZONE_HEADER = """
+ $SOA 0 example.org. hostmaster.example.com. 0 1h 1h 2d 1h
+@@ -113,7 +122,6 @@ class Rbldnsd(object):
+                                                  stderr=self.stderr)
+         # wait for rbldnsd to start responding
+-        time.sleep(0.1)
+         for retry in count():
+             if daemon.poll() is not None:
+                 raise DaemonError(
+@@ -124,12 +132,18 @@ class Rbldnsd(object):
+                 break
+             except QueryRefused:
+                 break
++            except DNS_SocketError as ex:
++                # pydns >= 2.3.6
++                wrapped_error = ex.args[0]
++                if wrapped_error.errno != errno.ECONNREFUSED:
++                    raise
+             except DNS.DNSError as ex:
++                # pydns < 2.3.6
+                 if str(ex) != 'no working nameservers found':
+                     raise
+-                elif retries > 10:
+-                    raise DaemonError(
+-                        "rbldnsd does not seem to be responding")
++            if retry > 10:
++                raise DaemonError("rbldnsd does not seem to be responding")
++            time.sleep(0.1)
+     def _stop_daemon(self):
+         daemon = self._daemon
+@@ -150,6 +164,22 @@ class Rbldnsd(object):
+             raise DaemonError("rbldnsd exited with code %d"
+                               % daemon.returncode)
++    @property
++    def no_ipv6(self):
++        """ Was rbldnsd compiled with -DNO_IPv6?
++        """
++        # If rbldnsd was compiled with -DNO_IPv6, the (therefore
++        # unsupported) '-6' command-line switch will not be described
++        # in the help message
++        cmd = [self.daemon_bin, '-h']
++        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
++        help_message = proc.stdout.readlines()
++        if proc.wait() != 0:
++            raise subprocess.CalledProcessError(proc.returncode, cmd)
++        return not any(line.lstrip().startswith('-6 ')
++                       for line in help_message)
++
++
+ class TestRbldnsd(unittest.TestCase):
+     def test(self):
+         rbldnsd = Rbldnsd()
+diff --git a/test_acl.py b/test_acl.py
+index d93ca0a..10bed1c 100644
+--- a/test_acl.py
++++ b/test_acl.py
+@@ -1,5 +1,8 @@
+ """ Tests for the acl dataset
+ """
++from functools import wraps
++import socket
++import sys
+ from tempfile import NamedTemporaryFile
+ import unittest
+@@ -9,6 +12,35 @@ __all__ = [
+     'TestAclDataset',
+     ]
++try:
++    from unittest import skipIf
++except ImportError:
++    # hokey replacement (for python <= 2.6)
++    def skipIf(condition, reason):
++        if condition:
++            def decorate(f):
++                @wraps(f)
++                def skipped(*args, **kw):
++                    sys.stderr.write("skipped test: %s " % reason)
++                return skipped
++            return decorate
++        else:
++            return lambda f: f
++
++def _have_ipv6():
++    # Check for IPv6 support
++    if not getattr(socket, 'has_ipv6', False):
++        return False                    # no python support for ipv6
++    elif Rbldnsd().no_ipv6:
++        return False                    # rbldnsd compiled with -DNO_IPv6
++    try:
++        socket.socket(socket.AF_INET6, socket.SOCK_DGRAM).close()
++    except socket.error:
++        return False                    # no kernel (or libc) support for ipv6?
++    return True
++
++no_ipv6 = not _have_ipv6()
++
+ def daemon(acl, addr='localhost'):
+     """ Create an Rbldnsd instance with given ACL
+     """
+@@ -33,11 +65,13 @@ class TestAclDataset(unittest.TestCase):
+                     addr='127.0.0.1') as dnsd:
+             self.assertEqual(dnsd.query('test.example.com'), 'Success')
++    @skipIf(no_ipv6, "IPv6 unsupported")
+     def test_refuse_ipv6(self):
+         with daemon(acl=["::1 :refuse"],
+                     addr='::1') as dnsd:
+             self.assertRaises(QueryRefused, dnsd.query, 'test.example.com')
++    @skipIf(no_ipv6, "IPv6 unsupported")
+     def test_pass_ipv6(self):
+         with daemon(acl=[ "0/0 :refuse",
+                           "0::1 :pass" ],
+diff --git a/test_ip4trie.py b/test_ip4trie.py
+index fe9e78f..2cce09b 100644
+--- a/test_ip4trie.py
++++ b/test_ip4trie.py
+@@ -9,7 +9,7 @@ __all__ = [
+     ]
+ def ip4trie(zone_data):
+-    """ Run rbldnsd with an ip6trie dataset
++    """ Run rbldnsd with an ip4trie dataset
+     """
+     dnsd = Rbldnsd()
+     dnsd.add_dataset('ip4trie', ZoneFile(zone_data))
+diff --git a/test_ip6trie.py b/test_ip6trie.py
+index d3600db..377c5dd 100644
+--- a/test_ip6trie.py
++++ b/test_ip6trie.py
+@@ -15,15 +15,6 @@ def ip6trie(zone_data):
+     dnsd.add_dataset('ip6trie', ZoneFile(zone_data))
+     return dnsd
+-def rfc3152(ip6addr, domain='example.com'):
+-    from socket import inet_pton, AF_INET6
+-    from struct import unpack
+-
+-    bytes = unpack("16B", inet_pton(AF_INET6, ip6addr))
+-    nibbles = '.'.join("%x.%x" % (byte & 0xf, (byte >> 4) & 0xf)
+-                       for byte in reversed(bytes))
+-    return "%s.%s" % (nibbles, domain)
+-
+ class TestIp6TrieDataset(unittest.TestCase):
+     def test_exclusion(self):
+         with ip6trie(["dead::/16 listed",
+@@ -31,5 +22,35 @@ class TestIp6TrieDataset(unittest.TestCase):
+             self.assertEqual(dnsd.query(rfc3152("dead::beef")), None)
+             self.assertEqual(dnsd.query(rfc3152("dead::beee")), "listed")
++
++def rfc3152(ip6addr, domain='example.com'):
++    return "%s.%s" % ('.'.join(reversed(_to_nibbles(ip6addr))), domain)
++
++def _to_nibbles(ip6addr):
++    """ Convert ip6 address (in rfc4291 notation) to a sequence of nibbles
++
++    NB: We avoid the use of socket.inet_pton(AF_INET6, ip6addr) here
++    because it fails (with 'error: can't use AF_INET6, IPv6 is
++    disabled') when python has been compiled without IPv6 support. See
++    http://www.corpit.ru/pipermail/rbldnsd/2013q3/001181.html
++
++    """
++    def _split_words(addr):
++        return [ int(w, 16) for w in addr.split(':') ] if addr else []
++
++    if '::' in ip6addr:
++        head, tail = [ _split_words(s) for s in ip6addr.split('::', 1) ]
++        nzeros = 8 - len(head) - len(tail)
++        assert nzeros >= 0
++        words = head + [ 0 ] * nzeros + tail
++    else:
++        words = _split_words(ip6addr)
++
++    assert len(words) == 8
++    for word in words:
++        assert 0 <= word <= 0xffff
++
++    return ''.join("%04x" % word for word in words)
++
+ if __name__ == '__main__':
+     unittest.main()
diff --git a/net-dns/rbldnsd/metadata.xml b/net-dns/rbldnsd/metadata.xml
new file mode 100644 (file)
index 0000000..2c45ca4
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+       <herd>proxy-maintainers</herd>
+       <maintainer>
+               <email>michael@orlitzky.com</email>
+               <name>Michael Orlitzky</name>
+               <description>Proxy Maintainer. CC on bugs.</description>
+       </maintainer>
+       <longdescription lang="en">
+               rbldnsd is a small and fast DNS daemon which is especially made to serve DNSBL
+               zones. This daemon was inspired by Dan J. Bernstein's rbldns program found in
+               the djbdns package.
+
+               rbldnsd is extremely fast - it outperforms both bind and djbdns greatly. It has
+               very small memory footprint.
+
+               The daemon can serve both IP-based (ordb.org, dsbl.org etc) and name-based
+               (rfc-ignorant.org) blocklists. Unlike DJB's rbldns, it has ability to specify
+               individual values for every entry, can serve as many zones on a single IP
+               address as you wish, and, finally, it is a real nameserver: it can reply to DNS
+               metadata requests. The daemon keeps all zones in memory for faster operations,
+               but its memory usage is very efficient, especially for repeated TXT values which
+               are stored only once.
+       </longdescription>
+</pkgmetadata>
diff --git a/net-dns/rbldnsd/rbldnsd-0.997a.ebuild b/net-dns/rbldnsd/rbldnsd-0.997a.ebuild
new file mode 100644 (file)
index 0000000..6011b00
--- /dev/null
@@ -0,0 +1,64 @@
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/net-dns/rbldnsd/rbldnsd-0.997.ebuild,v 1.3 2013/09/05 18:59:06 mgorny Exp $
+
+EAPI=5
+PYTHON_COMPAT=( python{2_6,2_7} )
+
+inherit eutils toolchain-funcs user python-single-r1
+
+DESCRIPTION="DNS server designed to serve blacklist zones"
+HOMEPAGE="http://www.corpit.ru/mjt/rbldnsd.html"
+SRC_URI="http://www.corpit.ru/mjt/rbldnsd/${P}.tar.gz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~amd64 ~hppa ~sparc ~x86 ~x86-fbsd"
+IUSE="ipv6 test zlib"
+
+RDEPEND="zlib? ( sys-libs/zlib )"
+DEPEND="${RDEPEND}
+       test? ( ${PYTHON_DEPS}
+               dev-python/pydns:2[${PYTHON_USEDEP}] )"
+
+src_prepare() {
+       epatch "${FILESDIR}/${P}-robust-ipv6-test-support.patch"
+}
+
+src_configure() {
+       # The ./configure file is handwritten and doesn't support a `make
+       # install` target, so there are no --prefix options. The econf
+       # function appends those automatically, so we can't use it.
+       ./configure \
+               $(use_enable ipv6) \
+               $(use_enable zlib) \
+               || die "./configure failed"
+}
+
+src_compile() {
+       emake \
+               AR="$(tc-getAR)" \
+               CC="$(tc-getCC)" \
+               RANLIB="$(tc-getRANLIB)"
+}
+
+src_test() {
+       emake check \
+               CC="$(tc-getCC)" \
+               PYTHON="${PYTHON}"
+}
+
+src_install() {
+       dosbin rbldnsd
+       doman rbldnsd.8
+       keepdir /var/db/rbldnsd
+       dodoc CHANGES* TODO NEWS README*
+       newinitd "${FILESDIR}"/initd-${PV} rbldnsd
+       newconfd "${FILESDIR}"/confd-${PV} rbldnsd
+}
+
+pkg_postinst() {
+       enewgroup rbldns
+       enewuser rbldns -1 -1 /var/db/rbldnsd rbldns
+       chown rbldns:rbldns /var/db/rbldnsd
+}