Skip to content
This repository was archived by the owner on Oct 21, 2022. It is now read-only.

Commit 2d7c9e4

Browse files
committed
Initial commit
0 parents  commit 2d7c9e4

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2014 Sam Stephenson, Basecamp
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#### xip-pdns
2+
3+
This is the source of the [PowerDNS](http://powerdns.com/) pipe backend adapter powering [xip.io](http://xip.io/).
4+
5+
Install this on your system, adjust [etc/xip-pdns.conf](etc/xip-pdns.conf.example) to your liking, and configure PowerDNS as follows:
6+
7+
launch=pipe
8+
pipe-command=/path/to/xip-pdns/bin/xip-pdns /path/to/xip-pdns/etc/xip-pdns.conf
9+

bin/xip-pdns

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
shopt -s nocasematch
4+
5+
#
6+
# Configuration
7+
#
8+
XIP_DOMAIN="xip.test"
9+
XIP_ROOT_ADDRESSES=( "127.0.0.1" )
10+
XIP_NS_ADDRESSES=( "127.0.0.1" )
11+
XIP_TIMESTAMP="0"
12+
XIP_TTL=300
13+
14+
if [ -a "$1" ]; then
15+
source "$1"
16+
fi
17+
18+
19+
#
20+
# Protocol helpers
21+
#
22+
read_cmd() {
23+
local IFS=$'\t'
24+
local i=0
25+
local arg
26+
27+
read -ra CMD
28+
for arg; do
29+
eval "$arg=\"\${CMD[$i]}\""
30+
let i=i+1
31+
done
32+
}
33+
34+
send_cmd() {
35+
local IFS=$'\t'
36+
printf "%s\n" "$*"
37+
}
38+
39+
fail() {
40+
send_cmd "FAIL"
41+
log "Exiting"
42+
exit 1
43+
}
44+
45+
read_helo() {
46+
read_cmd HELO VERSION
47+
[ "$HELO" = "HELO" ] && [ "$VERSION" = "1" ]
48+
}
49+
50+
read_query() {
51+
read_cmd TYPE QNAME QCLASS QTYPE ID IP
52+
}
53+
54+
send_answer() {
55+
local type="$1"
56+
shift
57+
send_cmd "DATA" "$QNAME" "$QCLASS" "$type" "$XIP_TTL" "$ID" "$@"
58+
}
59+
60+
log() {
61+
printf "[xip-pdns:$$] %s\n" "$@" >&2
62+
}
63+
64+
65+
#
66+
# xip.io domain helpers
67+
#
68+
XIP_DOMAIN_PATTERN="(^|\.)${XIP_DOMAIN//./\.}\$"
69+
NS_SUBDOMAIN_PATTERN="^ns-([0-9]+)\$"
70+
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]?))\$"
71+
BASE36_SUBDOMAIN_PATTERN="(^|\.)([a-z0-9]{1,7})\$"
72+
73+
qtype_is() {
74+
[ "$QTYPE" = "$1" ] || [ "$QTYPE" = "ANY" ]
75+
}
76+
77+
qname_matches_domain() {
78+
[[ "$QNAME" =~ $XIP_DOMAIN_PATTERN ]]
79+
}
80+
81+
qname_is_root_domain() {
82+
[ "$QNAME" = "$XIP_DOMAIN" ]
83+
}
84+
85+
extract_subdomain_from_qname() {
86+
SUBDOMAIN="${QNAME:0:${#QNAME}-${#XIP_DOMAIN}}"
87+
SUBDOMAIN="${SUBDOMAIN%.}"
88+
}
89+
90+
subdomain_is_ns() {
91+
[[ "$SUBDOMAIN" =~ $NS_SUBDOMAIN_PATTERN ]]
92+
}
93+
94+
subdomain_is_ip() {
95+
[[ "$SUBDOMAIN" =~ $IP_SUBDOMAIN_PATTERN ]]
96+
}
97+
98+
subdomain_is_base36() {
99+
[[ "$SUBDOMAIN" =~ $BASE36_SUBDOMAIN_PATTERN ]]
100+
}
101+
102+
resolve_ns_subdomain() {
103+
local index="${SUBDOMAIN:3}"
104+
echo "${XIP_NS_ADDRESSES[$index-1]}"
105+
}
106+
107+
resolve_ip_subdomain() {
108+
[[ "$SUBDOMAIN" =~ $IP_SUBDOMAIN_PATTERN ]] || true
109+
echo "${BASH_REMATCH[2]}"
110+
}
111+
112+
resolve_base36_subdomain() {
113+
[[ "$SUBDOMAIN" =~ $BASE36_SUBDOMAIN_PATTERN ]] || true
114+
local ip=$(( 36#${BASH_REMATCH[2]} ))
115+
printf "%d.%d.%d.%d" $(( ip&0xFF )) $(( (ip>>8)&0xFF )) $(( (ip>>16)&0xFF )) $(( (ip>>24)&0xFF ))
116+
}
117+
118+
answer_soa_query() {
119+
send_answer "SOA" "admin.$XIP_DOMAIN ns-1.$XIP_DOMAIN $XIP_TIMESTAMP $XIP_TTL $XIP_TTL $XIP_TTL $XIP_TTL"
120+
}
121+
122+
answer_ns_query() {
123+
local i=1
124+
local ns_address
125+
for ns_address in "${XIP_NS_ADDRESSES[@]}"; do
126+
send_answer "NS" "ns-$i.$XIP_DOMAIN"
127+
let i+=1
128+
done
129+
}
130+
131+
answer_root_a_query() {
132+
local address
133+
for address in "${XIP_ROOT_ADDRESSES[@]}"; do
134+
send_answer "A" "$address"
135+
done
136+
}
137+
138+
answer_subdomain_a_query_for() {
139+
local type="$1"
140+
local address="$(resolve_${type}_subdomain)"
141+
if [ -n "$address" ]; then
142+
send_answer "A" "$address"
143+
fi
144+
}
145+
146+
147+
#
148+
# PowerDNS pipe backend implementation
149+
#
150+
trap fail err
151+
read_helo
152+
send_cmd "OK" "xip.io PowerDNS pipe backend (protocol version 1)"
153+
154+
while read_query; do
155+
log "Query: type=$TYPE qname=$QNAME qclass=$QCLASS qtype=$QTYPE id=$ID ip=$IP"
156+
157+
if qname_matches_domain; then
158+
if qname_is_root_domain; then
159+
if qtype_is "SOA"; then
160+
answer_soa_query
161+
fi
162+
163+
if qtype_is "NS"; then
164+
answer_ns_query
165+
fi
166+
167+
if qtype_is "A"; then
168+
answer_root_a_query
169+
fi
170+
171+
elif qtype_is "A"; then
172+
extract_subdomain_from_qname
173+
174+
if subdomain_is_ns; then
175+
answer_subdomain_a_query_for ns
176+
177+
elif subdomain_is_ip; then
178+
answer_subdomain_a_query_for ip
179+
180+
elif subdomain_is_base36; then
181+
answer_subdomain_a_query_for base36
182+
fi
183+
fi
184+
fi
185+
186+
send_cmd "END"
187+
done

etc/xip-pdns.conf.example

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Increment this timestamp when the contents of the file change.
2+
XIP_TIMESTAMP="2014102800"
3+
4+
# The top-level domain for which the name server is authoritative.
5+
XIP_DOMAIN="xip.test"
6+
7+
# The public IP addresses (e.g. for the web site) of the top-level domain.
8+
# `A` queries for the top-level domain will return this list of addresses.
9+
XIP_ROOT_ADDRESSES=( "1.2.3.1" )
10+
11+
# The public IP addresses on which this xip-pdns server will run.
12+
# `NS` queries for the top-level domain will return this list of addresses.
13+
# Each entry maps to a 1-based subdomain of the format `ns-1`, `ns-2`, etc.
14+
# `A` queries for these subdomains map to the corresponding addresses here.
15+
XIP_NS_ADDRESSES=( "1.2.3.4" "1.2.3.5" )
16+
17+
# How long responses should be cached, in seconds.
18+
XIP_TTL=300

0 commit comments

Comments
 (0)