Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 2d7c9e412a8391ba6f8f868e2663d1dc2ce0506e @sstephenson sstephenson committed Oct 28, 2014
Showing with 234 additions and 0 deletions.
  1. +20 −0 LICENSE
  2. +9 −0 README.md
  3. +187 −0 bin/xip-pdns
  4. +18 −0 etc/xip-pdns.conf.example
@@ -0,0 +1,20 @@
+Copyright (c) 2014 Sam Stephenson, Basecamp
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,9 @@
+#### xip-pdns
+
+This is the source of the [PowerDNS](http://powerdns.com/) pipe backend adapter powering [xip.io](http://xip.io/).
+
+Install this on your system, adjust [etc/xip-pdns.conf](etc/xip-pdns.conf.example) to your liking, and configure PowerDNS as follows:
+
+ launch=pipe
+ pipe-command=/path/to/xip-pdns/bin/xip-pdns /path/to/xip-pdns/etc/xip-pdns.conf
+
@@ -0,0 +1,187 @@
+#!/usr/bin/env bash
+set -e
+shopt -s nocasematch
+
+#
+# Configuration
+#
+XIP_DOMAIN="xip.test"
+XIP_ROOT_ADDRESSES=( "127.0.0.1" )
+XIP_NS_ADDRESSES=( "127.0.0.1" )
+XIP_TIMESTAMP="0"
+XIP_TTL=300
+
+if [ -a "$1" ]; then
+ source "$1"
+fi
+
+
+#
+# Protocol helpers
+#
+read_cmd() {
+ local IFS=$'\t'
+ local i=0
+ local arg
+
+ read -ra CMD
+ for arg; do
+ eval "$arg=\"\${CMD[$i]}\""
+ let i=i+1
+ done
+}
+
+send_cmd() {
+ local IFS=$'\t'
+ printf "%s\n" "$*"
+}
+
+fail() {
+ send_cmd "FAIL"
+ log "Exiting"
+ exit 1
+}
+
+read_helo() {
+ read_cmd HELO VERSION
+ [ "$HELO" = "HELO" ] && [ "$VERSION" = "1" ]
+}
+
+read_query() {
+ read_cmd TYPE QNAME QCLASS QTYPE ID IP
+}
+
+send_answer() {
+ local type="$1"
+ shift
+ send_cmd "DATA" "$QNAME" "$QCLASS" "$type" "$XIP_TTL" "$ID" "$@"
+}
+
+log() {
+ printf "[xip-pdns:$$] %s\n" "$@" >&2
+}
+
+
+#
+# xip.io domain helpers
+#
+XIP_DOMAIN_PATTERN="(^|\.)${XIP_DOMAIN//./\.}\$"
+NS_SUBDOMAIN_PATTERN="^ns-([0-9]+)\$"
+IP_SUBDOMAIN_PATTERN="(^|\.)(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\$"
+BASE36_SUBDOMAIN_PATTERN="(^|\.)([a-z0-9]{1,7})\$"
+
+qtype_is() {
+ [ "$QTYPE" = "$1" ] || [ "$QTYPE" = "ANY" ]
+}
+
+qname_matches_domain() {
+ [[ "$QNAME" =~ $XIP_DOMAIN_PATTERN ]]
+}
+
+qname_is_root_domain() {
+ [ "$QNAME" = "$XIP_DOMAIN" ]
+}
+
+extract_subdomain_from_qname() {
+ SUBDOMAIN="${QNAME:0:${#QNAME}-${#XIP_DOMAIN}}"
+ SUBDOMAIN="${SUBDOMAIN%.}"
+}
+
+subdomain_is_ns() {
+ [[ "$SUBDOMAIN" =~ $NS_SUBDOMAIN_PATTERN ]]
+}
+
+subdomain_is_ip() {
+ [[ "$SUBDOMAIN" =~ $IP_SUBDOMAIN_PATTERN ]]
+}
+
+subdomain_is_base36() {
+ [[ "$SUBDOMAIN" =~ $BASE36_SUBDOMAIN_PATTERN ]]
+}
+
+resolve_ns_subdomain() {
+ local index="${SUBDOMAIN:3}"
+ echo "${XIP_NS_ADDRESSES[$index-1]}"
+}
+
+resolve_ip_subdomain() {
+ [[ "$SUBDOMAIN" =~ $IP_SUBDOMAIN_PATTERN ]] || true
+ echo "${BASH_REMATCH[2]}"
+}
+
+resolve_base36_subdomain() {
+ [[ "$SUBDOMAIN" =~ $BASE36_SUBDOMAIN_PATTERN ]] || true
+ local ip=$(( 36#${BASH_REMATCH[2]} ))
+ printf "%d.%d.%d.%d" $(( ip&0xFF )) $(( (ip>>8)&0xFF )) $(( (ip>>16)&0xFF )) $(( (ip>>24)&0xFF ))
+}
+
+answer_soa_query() {
+ send_answer "SOA" "admin.$XIP_DOMAIN ns-1.$XIP_DOMAIN $XIP_TIMESTAMP $XIP_TTL $XIP_TTL $XIP_TTL $XIP_TTL"
+}
+
+answer_ns_query() {
+ local i=1
+ local ns_address
+ for ns_address in "${XIP_NS_ADDRESSES[@]}"; do
+ send_answer "NS" "ns-$i.$XIP_DOMAIN"
+ let i+=1
+ done
+}
+
+answer_root_a_query() {
+ local address
+ for address in "${XIP_ROOT_ADDRESSES[@]}"; do
+ send_answer "A" "$address"
+ done
+}
+
+answer_subdomain_a_query_for() {
+ local type="$1"
+ local address="$(resolve_${type}_subdomain)"
+ if [ -n "$address" ]; then
+ send_answer "A" "$address"
+ fi
+}
+
+
+#
+# PowerDNS pipe backend implementation
+#
+trap fail err
+read_helo
+send_cmd "OK" "xip.io PowerDNS pipe backend (protocol version 1)"
+
+while read_query; do
+ log "Query: type=$TYPE qname=$QNAME qclass=$QCLASS qtype=$QTYPE id=$ID ip=$IP"
+
+ if qname_matches_domain; then
+ if qname_is_root_domain; then
+ if qtype_is "SOA"; then
+ answer_soa_query
+ fi
+
+ if qtype_is "NS"; then
+ answer_ns_query
+ fi
+
+ if qtype_is "A"; then
+ answer_root_a_query
+ fi
+
+ elif qtype_is "A"; then
+ extract_subdomain_from_qname
+
+ if subdomain_is_ns; then
+ answer_subdomain_a_query_for ns
+
+ elif subdomain_is_ip; then
+ answer_subdomain_a_query_for ip
+
+ elif subdomain_is_base36; then
+ answer_subdomain_a_query_for base36
+ fi
+ fi
+ fi
+
+ send_cmd "END"
+done
@@ -0,0 +1,18 @@
+# Increment this timestamp when the contents of the file change.
+XIP_TIMESTAMP="2014102800"
+
+# The top-level domain for which the name server is authoritative.
+XIP_DOMAIN="xip.test"
+
+# The public IP addresses (e.g. for the web site) of the top-level domain.
+# `A` queries for the top-level domain will return this list of addresses.
+XIP_ROOT_ADDRESSES=( "1.2.3.1" )
+
+# The public IP addresses on which this xip-pdns server will run.
+# `NS` queries for the top-level domain will return this list of addresses.
+# Each entry maps to a 1-based subdomain of the format `ns-1`, `ns-2`, etc.
+# `A` queries for these subdomains map to the corresponding addresses here.
+XIP_NS_ADDRESSES=( "1.2.3.4" "1.2.3.5" )
+
+# How long responses should be cached, in seconds.
+XIP_TTL=300

0 comments on commit 2d7c9e4

Please sign in to comment.