Initial commit
This commit is contained in:
commit
2d7c9e412a
|
@ -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
|
Loading…
Reference in New Issue