├── bind ├── named.conf └── named.conf.options ├── templates ├── nsupdate.key.j2 ├── dnsbin.ini.j2 ├── named.conf.local.j2 └── db.blank_zone.j2 ├── requirements.txt ├── start_dnsbin.sh ├── LICENSE ├── scripts └── run.sh ├── Dockerfile ├── api ├── api.py ├── routes │ ├── __init__.py │ └── paste.py └── utils │ ├── middlewares │ ├── __init__.py │ └── json_middlewares.py │ ├── app.py │ ├── __init__.py │ ├── error_handler.py │ └── logger.py ├── .travis.yml └── README.md /bind/named.conf: -------------------------------------------------------------------------------- 1 | include "/etc/bind/named.conf.options"; 2 | include "/etc/bind/named.conf.local"; 3 | -------------------------------------------------------------------------------- /templates/nsupdate.key.j2: -------------------------------------------------------------------------------- 1 | key "{{ DNS_KEY_NAME }}" { 2 | algorithm "{{ DNS_KEY_ALGO }}"; 3 | secret "{{ DNS_KEY_SECRET }}"; 4 | }; 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dnspython==1.12.0 2 | falcon==0.3.0 3 | gunicorn==19.4.1 4 | j2cli==0.3.1-0 5 | Jinja2==2.8 6 | MarkupSafe==0.23 7 | python-mimeparse==0.1.4 8 | six==1.10.0 9 | -------------------------------------------------------------------------------- /templates/dnsbin.ini.j2: -------------------------------------------------------------------------------- 1 | [key] 2 | name = {{ DNS_KEY_NAME }} 3 | secret = {{ DNS_KEY_SECRET }} 4 | algo = {{ DNS_KEY_ALGO }} 5 | 6 | [server] 7 | address = 127.0.0.1 8 | zone = {{ DNS_ZONE }} 9 | -------------------------------------------------------------------------------- /templates/named.conf.local.j2: -------------------------------------------------------------------------------- 1 | include "/etc/bind/nsupdate.key"; 2 | 3 | zone "{{ DNS_ZONE }}" { 4 | type master; 5 | file "/var/cache/bind/db.{{ DNS_ZONE }}"; 6 | allow-update { 7 | key "{{ DNS_KEY_NAME }}"; 8 | }; 9 | check-names fail; 10 | }; 11 | -------------------------------------------------------------------------------- /bind/named.conf.options: -------------------------------------------------------------------------------- 1 | options { 2 | directory "/var/cache/bind"; 3 | listen-on { any; }; 4 | listen-on-v6 { none; }; 5 | allow-query-cache { any; }; 6 | recursion no; 7 | allow-recursion { none; }; 8 | allow-transfer { none; }; 9 | }; 10 | -------------------------------------------------------------------------------- /start_dnsbin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run \ 4 | --name=dnsbin \ 5 | --rm=true \ 6 | --net=host \ 7 | -e DNS_ZONE=paste \ 8 | -e DNS_KEY_ALGO=hmac-sha512 \ 9 | -e DNS_KEY_NAME=paste \ 10 | -e DNS_KEY_SECRET="974Dq4TkBfv50g7zLvBH+5Fx+Sngl27IPxIb5tuLjErm34nWyW07ACKqdYTafvAXFkHI3HzRFOV5Zz18Zuvw1w==" \ 11 | -it dnsbin 12 | -------------------------------------------------------------------------------- /templates/db.blank_zone.j2: -------------------------------------------------------------------------------- 1 | $TTL 10 ; 10 seconds 2 | @ IN SOA master.{{ DNS_ZONE }}. admin.{{ DNS_ZONE }}. ( 3 | 1 ; serial 4 | 604800 ; refresh (1 week) 5 | 60 ; retry (5 minutes) 6 | 2419200 ; expire (4 weeks) 7 | 10 ; minimum (10 seconds) 8 | ) 9 | 10 | master IN A 127.0.0.1 11 | @ IN NS master.{{ DNS_ZONE }}. 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2015 Thomas Maurice 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! [ -f /var/cache/bind/db.$DNS_ZONE ]; then 4 | j2 -f env /templates/db.blank_zone.j2 > /var/cache/bind/db.$DNS_ZONE 5 | chown named:named /var/cache/bind/db.$DNS_ZONE 6 | fi; 7 | 8 | j2 -f env /templates/named.conf.local.j2 > /etc/bind/named.conf.local 9 | j2 -f env /templates/nsupdate.key.j2 > /etc/bind/nsupdate.key 10 | j2 -f env /templates/dnsbin.ini.j2 > /etc/dnsbin.ini 11 | 12 | gunicorn \ 13 | -b :80 \ 14 | -w 32 \ 15 | --chdir /usr/app \ 16 | --access-logfile /dev/stdout \ 17 | --error-logfile /dev/stdout \ 18 | api:app & 19 | /usr/sbin/named -u named -g -4 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | MAINTAINER Thomas Maurice 3 | 4 | RUN apk update && \ 5 | apk add \ 6 | bind \ 7 | python \ 8 | python-dev \ 9 | py-pip 10 | 11 | COPY requirements.txt /requirements.txt 12 | 13 | RUN pip install -r /requirements.txt 14 | 15 | RUN mkdir -p /var/run/named /templates /var/cache/bind 16 | COPY bind/named.conf.options bind/named.conf /etc/bind/ 17 | RUN chown -R named:named /var/run/named /etc/bind/ /var/cache/bind 18 | COPY templates/*.j2 update_scripts/*.j2 /templates/ 19 | COPY scripts/run.sh /run.sh 20 | COPY api /usr/app/ 21 | 22 | EXPOSE 53 80 23 | 24 | CMD /run.sh 25 | -------------------------------------------------------------------------------- /api/api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | from utils import app 21 | import routes 22 | -------------------------------------------------------------------------------- /api/routes/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | import paste 21 | from utils import app 22 | 23 | app.add_route('/paste', paste.Paste()) 24 | -------------------------------------------------------------------------------- /api/utils/middlewares/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | import json_middlewares 21 | 22 | middlewares = [json_middlewares.JSONOutput(), json_middlewares.JSONInput()] 23 | -------------------------------------------------------------------------------- /api/utils/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | import sys 21 | import os 22 | import falcon 23 | import json 24 | 25 | from middlewares import middlewares 26 | from error_handler import error_handler 27 | 28 | app = falcon.API(middleware=middlewares) 29 | app.add_error_handler(Exception, error_handler) 30 | app.add_error_handler(falcon.HTTPError, error_handler) 31 | -------------------------------------------------------------------------------- /api/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | import falcon 21 | from app import app 22 | from middlewares import middlewares 23 | from error_handler import error_handler 24 | from logger import setup_logger 25 | 26 | app = falcon.API(middleware=middlewares) 27 | app.add_error_handler(Exception, error_handler) 28 | app.add_error_handler(falcon.HTTPError, error_handler) 29 | -------------------------------------------------------------------------------- /api/utils/error_handler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | import sys 21 | import os 22 | import falcon 23 | import json 24 | import traceback 25 | 26 | def error_handler(exce, req, resp, params): 27 | if issubclass(exce.__class__, falcon.HTTPError): 28 | resp.status = exce.status 29 | req.context['result'] = {'error': "%s: %s" % (exce.title, exce.description)} 30 | else: 31 | print traceback.print_exc() 32 | resp.status = falcon.HTTP_500 33 | req.context['result'] = {'error': str(traceback.format_exc())} 34 | -------------------------------------------------------------------------------- /api/utils/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | Version 2, December 2004 6 | 7 | Copyright (C) 2015 Thomas Maurice 8 | 9 | Everyone is permitted to copy and distribute verbatim or modified 10 | copies of this license document, and changing it is allowed as long 11 | as the name is changed. 12 | 13 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 14 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 15 | 16 | 0. You just DO WHAT THE FUCK YOU WANT TO. 17 | """ 18 | 19 | import logging 20 | 21 | def setup_logger(name, to_stdout=True, file_name=None): 22 | """Creates the logging object used by the script 23 | 24 | By defaults it prints information ton stdout, but 25 | you can tell it to print out information ton a file too 26 | """ 27 | logger = logging.getLogger(name) 28 | logger.setLevel(logging.DEBUG) 29 | formatter = logging.Formatter( 30 | '%(asctime)s %(levelname)s: %(message)s' 31 | ) 32 | 33 | # reset handlers 34 | for handler in logger.handlers: 35 | # Don't close stdout or stderr ! 36 | if handler.__class__ != logging.StreamHandler: 37 | handler.stream.close() 38 | logger.removeHandler(handler) 39 | 40 | if file_name: 41 | fhandle = logging.FileHandler(file_name) 42 | fhandle.setLevel(logging.DEBUG) 43 | fhandle.setFormatter(formatter) 44 | logger.addHandler(fhandle) 45 | 46 | if to_stdout: 47 | chandle = logging.StreamHandler() 48 | chandle.setLevel(logging.DEBUG) 49 | chandle.setFormatter(formatter) 50 | logger.addHandler(chandle) 51 | 52 | return logger 53 | -------------------------------------------------------------------------------- /api/utils/middlewares/json_middlewares.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | import sys 21 | import os 22 | import falcon 23 | import json 24 | 25 | class JSONInput(object): 26 | def process_request(self, req, resp): 27 | if req.method in ['GET', 'HEAD', 'OPTIONS']: 28 | return 29 | 30 | body = req.stream.read() 31 | if not body: 32 | raise falcon.HTTPBadRequest('Empty request body', 33 | 'A valid JSON document is required.') 34 | try: 35 | req.context['json'] = json.loads(body.decode('utf-8')) 36 | except (ValueError, UnicodeDecodeError) as exce: 37 | raise falcon.HTTPError(falcon.HTTP_400, 38 | 'Malformed JSON', 39 | 'Could not decode the request body. The ' 40 | 'JSON was incorrect or not encoded as ' 41 | 'UTF-8.') 42 | 43 | class JSONOutput(object): 44 | def process_response(self, req, resp, resource): 45 | if 'result' not in req.context: 46 | return 47 | 48 | resp.body = json.dumps({'status': int(resp.status.split(' ')[0]), 49 | 'data': req.context['result'] 50 | }) 51 | -------------------------------------------------------------------------------- /api/routes/paste.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2015 Thomas Maurice 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | """ 19 | 20 | from utils import setup_logger 21 | import ConfigParser 22 | import dns.tsigkeyring 23 | import dns.query 24 | import dns.update 25 | import dns.zone 26 | import base64 27 | import falcon 28 | import uuid 29 | import os 30 | 31 | LOGGER = setup_logger("dnsbin") 32 | 33 | CONFIG = ConfigParser.ConfigParser() 34 | CONFIG.read('/etc/dnsbin.ini') 35 | 36 | KEYRING = dns.tsigkeyring.from_text({ 37 | CONFIG.get('key', 'name') : CONFIG.get('key', 'secret') 38 | }) 39 | 40 | def chunks(l, n): 41 | for i in xrange(0, len(l), n): 42 | yield l[i:i+n] 43 | 44 | class Paste(object): 45 | def on_post(self, req, resp): 46 | update = dns.update.Update( 47 | CONFIG.get('server', 'zone'), 48 | keyring=KEYRING, 49 | keyalgorithm=CONFIG.get('key', 'algo') 50 | ) 51 | 52 | body = req.context['json']['data'] 53 | LOGGER.info("Received %d byte long paste" % len(body)) 54 | try: 55 | base64.b64decode(body.decode("ascii")) 56 | except Exception: 57 | raise falcon.HTTPBadRequest("Wrong encoding", "Your data is not base64 encoded !") 58 | 59 | uid = str(uuid.uuid4()) 60 | i = 0 61 | for chunk in chunks(body, 255): 62 | i += 1 63 | LOGGER.info("Registering chunk %d of paste %s : %s" % (i, uid, chunk)) 64 | update.replace("%d.%s" % (i, uid), 10, 'TXT', str(chunk)) 65 | response = dns.query.tcp(update, CONFIG.get('server', 'address')) 66 | LOGGER.info("Registering chunk number of paste %s" % uid) 67 | update.replace("%s" % uid, 10, 'TXT', "%d" % i) 68 | response = dns.query.tcp(update, CONFIG.get('server', 'address')) 69 | req.context['result'] = {"paste": uid} 70 | LOGGER.info("Paste %s registered !" % uid) 71 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | - secure: BVTdzR/ApepZ4VZ8VIwUpyIr1NpnpcTh4Tb2jgqBB8EWnQVpA1i8tWwSUI5Oj2rgmcI97qDWQXGHxXOjC9/0SiMNsl1QoTtXs1bFG2SvJtmWrCAfR91MLB0yAwvZCA0opLuCtItHoAfwmSQrjW8s+nnCVNYdUw1J1HyR7/84/jlD2CGwGNMvhzZJ1Xl3vacVBOpQt+DDnAAz8419cUJPn4hD3dr3otpBfGWHO49RAqoryEbiQdmgR/hS0YCpWSy0yOQS5dzsqZR+bwE64TdNb/PdVslJRq1u+Y64e1owrAGAbCWx/nEB4qsmpvrZMQhvK1IJ4nLlNWukOqP+Z22g+e3FcuZtDwRDTyePjEitUjJM3tDFGtRPwg6juLGDsiC98mUpJiC0ToJCsIPaVWxaC4Mmnt0T01hex2Vdv4rmY+f8dyC5GEJWHtE3ucZOqlLRYUIKjkYfPm+pnJLl2TTZ+x7GCbbg0m9q/vne/Jn1KGu7HbjIrrZeGwWDX8sy6cLeojIql5uodA5O7VFwmOMnUPL66EyulQ1Herc7ojejozmUq23DB7an+FRYnA0IXqRDOpPUQMc0Qb2GbNpqQgSDMDBl/+LC7do82XNj5zbPUky2dwqjG6FiJx4mjov7Xved9UDxviz1kXisuqd6dMk+r86mvFiM5GrLzIeWOTU7/nU= 4 | - secure: lFIbmsG0Nx+lAziSpqQK5cIZ1e8WDDrgaWJVgtlWsQKGi2abmRaoiuF7bzvxOa2fP+L9fw/VERUSj1w0CcS6zFsWdZ2F7tuUJZ3+O56hSPaO21OmwpoxhjK8BNmCwPu7Cqdq0kl4Vdv0H2EVRAeqzPeakowaJx3ARjbGIa0NI3EnzwplKzbh9scTXewes39TACb6l95lZt647eBbuaSIWHSH51MzlNIZQzErTBZ58nLqvuhlEpI5sSkoDeyXaGoRZ7yP0OBWP0Kp4s0sm163Xo4QkmrzRxiD9NXO9UkGDfkpDwYXKF4CZqW1tS4xl74Dy1hvgxzxLAGz4krprEMqyyTsqqy2LTXzzbq8+nnkuwOOFsYEZDU6/jigZltb/ZjUXf5p4XgvX/BdEk5R5XetKFMZCpxWVFzY3Ym/KUJT+6ttQ0s898s7/URcC83aVhrdPaJUT+47Q4xzGaWss7OZjDn6Pu0ajtT2u6PEDdBtMTcBZNhWL+Hiqti2o2tqGCuKNBI7t4UC2RA41IWCMgXMdpY06UeGb5OTiz/6mP3vhIMKwS8g24SXedy+gpnOtIM7R3VWZ7MMlf36n6qVeLamIWll1Na3RuAX3jCYnw0Pfj77aZUuEd8+Xo/2q9hxqrgrreoqTSnvd0wsjRxuYd8wJM2aW4cCWffVVZwlJHeGLY0= 5 | - secure: Hyq3DFwmeNVxjM821zARVrbBQ2Wr3W9/4B3c/cRuwHnc3iOee8BJBJpOHK9FICjT3bVVWqTJW5uwzD9JZXgN943lwut6X50ebsi/p3eL2Tt7ZH/aADOr2I9pyOnqDRkoSyBbgaEzps98uDfgKx5uW3md4N7L63KqXSeMOsmv8aT31Fky9olEnysd0Bx5+8KRmT46D4wdfuNfP4I469Kxx2Cofto//EtMYEs6GJLUTCGpGpQ5amf2/GkZeFCS2Zii60R35woAGp5bd8ehjFEt4uRax9AsfNbLb2SA6SYRjpd6bAmKbBPL2BmCyN1npfB+JRgx8oPRbcU/smYPG5SiidQz4eJp0DfaCmPoz62oHDgwlaqBLyNVA0R2ApbtyfzeB6WMona7qsXDv79MDwqhJcAM52iJ6U7SDFu5nZ8PXMQIYfL+8U59sANDTns9Gz0StgwQvjUG+9ZW6CMMy4DKL4H2LEEMTsKBk8Mxi5HjNUfyrFbbYsDMxaRDDbUCz6EIlkHQa71ayf1EtWE5ajZs+CjQ1vNtlpszbkdSrhQlm/420DwwJZ+A/7FbGH6kg0ie9JiA+RsvUk7SUruDcsyawk2LVIB74wILHwoVW+1IPTejtv02mMk4OM5N3RmpBSyHeoH+2a3jaQZSp0zhuw5sDdWU1a2zcqyR1rEpfeEmetM= 6 | - COMMIT=${TRAVIS_COMMIT::8} 7 | sudo: required 8 | services: 9 | - docker 10 | install: 11 | - docker pull alpine 12 | script: 13 | - docker build -t tmaurice/dnsbin:$COMMIT . 14 | - docker images 15 | after_success: 16 | - docker login -e "$DOCKER_EMAIL" -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD" 17 | - docker tag tmaurice/dnsbin:$COMMIT tmaurice/dnsbin:latest 18 | - docker push tmaurice/dnsbin:$COMMIT 19 | - docker push tmaurice/dnsbin:latest 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dnsbin 2 | [![Build Status](https://travis-ci.org/thomas-maurice/dnsbin.svg)](https://travis-ci.org/thomas-maurice/dnsbin) 3 | [![Docker Pulls](https://img.shields.io/docker/pulls/tmaurice/dnsbin.svg)](https://hub.docker.com/r/tmaurice/dnsbin/) 4 | 5 | The most useless and under optimized pastebin ever known to mankind. 6 | 7 | # Introduction 8 | dnsbin is a pastebin based on DNS. It means that you 9 | can submit a paste using a basic HTTP api, and 10 | retrieving it via DNS requests. 11 | 12 | ## What's the concept ? 13 | The concept is quite simple, it uses the DNS protocol (and more especially the TXT 14 | data field) to store any arbitrary data. This is silly but also interesting since 15 | DNS has to be the less filtered protocol ever (unless you live in China, lol) and 16 | benefits from la native caching system. 17 | 18 | That means you virtually have a free CDN :) (Eventough this functionality has not 19 | been developped yet, see TODO) 20 | 21 | It has initially be developped to be some kind of under-optimized pastebin system but since 22 | you can store any ASCII data in TXT fields, you can upload base64 encoded binary files 23 | if you want. Bittorrent is dead :D 24 | 25 | (or not.) 26 | 27 | ## Why would you do that ? 28 | Because I could :3 29 | 30 | # How to install it ? 31 | Just build the Dockerfile : 32 | ```bash 33 | docker build -t dnsbin . 34 | ``` 35 | 36 | *Alternatively* you can now just perform a docker pull tmaurice/dnsbin 37 | 38 | And run it : 39 | ```bash 40 | ./start_dnsbin.sh 41 | ``` 42 | 43 | And you're done ! 44 | 45 | # Using the commandline 46 | To use the commandline please refer to the documentation there : https://github.com/thomas-maurice/dnsbin-cli 47 | 48 | # Customizing it 49 | You can customize the docker setting up some parameters in the startup script. 50 | Currently the only one you can play with is the TSIG key used to update the server 51 | which I actually advise you to change if you plan on putting the server online. 52 | You can generate a new key via 53 | ```bash 54 | dnssec-keygen -a HMAC-SHA512 -b 512 -r /dev/urandom -n HOST keyname 55 | ``` 56 | 57 | If you don't, anyone could push updates to your zone. 58 | 59 | # How does it work under the hood ? 60 | The bind DNS server registers a "local" zone .paste that 61 | he thinks he is rightful to authoritate on. 62 | 63 | I don't quite think that in the current implementation 64 | fqdn chunks are supported, but let me know if you find 65 | a way to do it, I'll try to implement it sometime ! 66 | 67 | The HTTP API uses TSIG keys to post update to the zone 68 | everytime you want to get a paste. The paste is encoded 69 | with base64 and chunked into pieces to fit into the TXT 70 | fields of the DNS. 71 | 72 | Then for each post you get *uuid.paste* which contains 73 | the number of chunks the paste has, and then *1.uuid*, 74 | *2.uuid* ... *N.uuid* containing each chunk. 75 | 76 | That is almost as stupid as simple :) 77 | 78 | # TODO 79 | * Support "fqdn pastes", that will allow you to 80 | query Google's own 8.8.8.8 for *someuuid*.yourdomain.com :) 81 | * DNSSEC \o/ 82 | * Add a pastes.paste endpoint listing all the pastes 83 | * Add a mechanism to purge old pastes 84 | * Add a way to parallelize upload 85 | * Support to chunk big content into multiple pastes and store 86 | the references of this pastes in the "master paste" 87 | * Add some metadata to the pastes somehow 88 | --------------------------------------------------------------------------------