commit 09c0e7a6f035cb4d55e97b478f87ade89d4752e6 Author: John-Mark Gurney Date: Sat Dec 7 23:07:06 2019 -0800 initial work on privrdns... Need to look at a different dns library, as this one doesn't do DNSSEC validation... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2dd755 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.coverage +*.pyc +privrdns.egg-info +p diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4418752 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +PROJNAME=privrdns +VIRTUALENV ?= virtualenv-3.7 +VRITUALENVARGS = + +FILES=$(PROJNAME)/__init__.py + +test: + (echo $(FILES) | entr sh -c 'python -m coverage run -m unittest $(PROJNAME) && coverage report --omit=p/\* -m -i') + +test-noentr: + python -m coverage run -m unittest $(PROJNAME) && coverage report --omit=p/\* -m -i + +env: + ($(VIRTUALENV) $(VIRTUALENVARGS) p && . ./p/bin/activate && pip install -r requirements.txt) diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 0000000..5f8af63 --- /dev/null +++ b/NOTES.md @@ -0,0 +1 @@ +https://github.com/paulc/dnslib diff --git a/README.md b/README.md new file mode 100644 index 0000000..27dd284 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +Privacy for recursive DNS +========================= + +DNS is currently unsecured, and the IETF have only just started attempting to solve this problem, [Signaling That an Authoritative DNS server offers DoT](https://datatracker.ietf.org/doc/draft-levine-dprive-signal/). DoH doesn't actually solve the problem, it just moves it around. + +Even when Authoratative DoT is a thing, there will be plenty of domains that will take years, if not decades before it'll be rolled out. + +One solution is to use tor to anonymize the DNS queries. This will only work w/ DNSSEC domains, though there is the option that a voting system could be used, say make 5 queries through different exit nodes, and if any of them disagree, do additional queries to validate the solution. diff --git a/privrdns/__init__.py b/privrdns/__init__.py new file mode 100644 index 0000000..f53d02a --- /dev/null +++ b/privrdns/__init__.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# +# Copyright 2019 John-Mark Gurney. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +__author__ = 'John-Mark Gurney' +__copyright__ = 'Copyright 2019 John-Mark Gurney. All rights reserved.' +__license__ = '2-clause BSD license' +__version__ = '0.1.0.dev' + +import asyncio +import unittest + +from dnslib import DNSRecord, RR, QTYPE, A, digparser +from ntunnel import async_test, parsesockstr + +class DNSProc(asyncio.DatagramProtocol): + def connection_made(self, transport): + print('cm') + self.transport = transport + + def datagram_received(self, data, addr): + print('dr') + pkt = DNSRecord.parse(data) + print(repr((pkt, addr))) + + d = pkt.reply() + d.add_answer(RR("xxx.abc.com",QTYPE.A,rdata=A("1.2.3.4"))) + data = d.pack() + self.transport.sendto(data, addr) + +async def dnsprocessor(sockstr): + proto, args = parsesockstr(sockstr) + + if proto == 'udp': + loop = asyncio.get_event_loop() + print('pre-cde') + trans, protocol = await loop.create_datagram_endpoint(DNSProc, + local_addr=(args.get('host', '127.0.0.1'), args['port'])) + print('post-cde', repr((trans, protocol)), trans is protocol.transport) + else: + raise ValueError('unknown protocol: %s' % repr(proto)) + +class Tests(unittest.TestCase): + @async_test + async def test_processdnsfailures(self): + port = 5 + with self.assertRaises(ValueError): + dnsproc = await dnsprocessor( + 'tcp:host=127.0.0.1,port=%d' % port) + print('post-dns') + + @async_test + async def test_processdns(self): + # start the dns processor + port = 38394 + dnsproc = await dnsprocessor( + 'udp:host=127.0.0.1,port=%d' % port) + + # submit a query to it + digproc = await asyncio.create_subprocess_exec('dig', + '@127.0.0.1', '-p', str(port), '+dnssec', '+time=1', + 'www.funkthat.com.', + stdout=asyncio.subprocess.PIPE) + + # make sure it exits successfully + self.assertEqual(await digproc.wait(), 0) + + stdout, stderr = await digproc.communicate() + + rep = list(digparser.DigParser(stdout)) + self.assertEqual(len(rep), 1) + print('x', repr(list(rep))) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c518e6b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# use setup.py for dependancy info +-e . + +-e .[dev] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ca207a3 --- /dev/null +++ b/setup.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +def getversion(fname): + with open(fname) as fp: + v = [ x for x in fp.readlines() if x.startswith('__version__') ] + if len(v) != 1: + raise ValueError('too many lines start with __version__') + return v[0].split("'")[1] + +from setuptools import setup +import os.path +__version__ = getversion(os.path.join('privrdns', '__init__.py')) + +# Install requirements for git: +# https://stackoverflow.com/questions/18026980/python-setuptools-how-can-i-list-a-private-repository-under-install-requires + +setup(name='privrdns', + version=__version__, + description='A socket tunning tool using the Noise Protocol', + author='John-Mark Gurney', + author_email='jmg@funkthat.com', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: BSD License', + 'Topic :: Security', + 'Topic :: System :: Networking', + 'Topic :: Utilities', + ], + url='https://www.funkthat.com/gitea/jmg/privrdns', + packages=[ 'privrdns', ], + python_requires='~=3.7', + install_requires=[ + 'ntunnel @ git+https://www.funkthat.com/gitea/jmg/ntunnel.git@c203547c28e935d11855601ce4e4f31db4e9065d', + 'dnslib @ git+https://github.com/paulc/dnslib.git' + ], + extras_require = { + 'dev': [ 'coverage' ], + }, + entry_points={ + 'console_scripts': [ + 'privrdns = privrdns.__main__:main', + ] + } +)