#!/usr/bin/ruby # This script generates a djbdns tinydns data file, with ipv6 support # You still need an ipv6 patch for tcpserver if you want to handle queries over ipv6 # Yoann Guillot, 04/2007, license: wtfpl # some variables for frequently-used ips intip = '192.168.7.1' extip = '82.227.12.18' extip6 = '2002:%x%02x:%x%02x::1' % extip.split('.') # 6to4 address # # public # nsname = 'a.ns.ofjj.net' # the machine hosting the server ns 'ofjj.net', nsname # authoritative forward ns arpa6(extip6, 12), nsname # authoritative for reverse ipv6 (check 6to4.nro.net) a nsname, extip aaaa nsname, extip6 # ensure tinydns listens on ipv6 mxname = 'a.mx.ofjj.net' # mx entry mx 'ofjj.net', mxname a mxname, extip aaaa mxname, extip6 # ensure your smtp listens on ipv6 # the last non-arpa ns zone is used as default suffix for non-'.' names host 'thebox', extip # machine definitions host6 'thebox', extip6 a 'ofjj.net', extip aaaa 'ofjj.net', extip6 a 'vpn', extip a 'ipv4', extip aaaa 'ipv6', extip6 # # internal # localto('192.168.7', '127') { insname = 'a.ns.jj' ns 'jj', insname ns arpa(intip, 3), insname a insname, intip host 'jjbox', intip host 'station', '192.168.7.12' a 'www', intip } # write text file Dir.chdir '/service/tinydns/root' File.open('data.new', 'w') { |fd| fd.puts $data.map { |l| l.join(':') } fd.fsync } File.rename('data.new', 'data') system 'tinydns-data' # create db file # restart cache server (TODO find a way to just flush its cache) system 'svc -t /service/dnscache' puts 'done' BEGIN { # this holds the data to be written to the file $data = [] # default suffix for hostnames without a '.' -- set by ns() $suffix = '' # default client location specification (for split views) -- use with localto() { } $lo = nil # client-specific configuration (aka 'views') # longest prefix takes precedence # non-localto definitions are global # ex: localto('192.168', '127') { host 'foo.com', '192.168.0.1' } ; localto { host 'foo.com', '1.2.3.4' } # works by temporarily rewriting $lo (prefixes are cached, so you may safely use multiple blocks with same prefix) def localto(*prefixes) prefixes << '' if prefixes.empty? prefixes.each { |prefix| # generate new prefix $lomap ||= {} if not mylo = $lomap.index(prefix) if $lomap.empty? mylo = 'aa' else mylo = $lomap.keys.last.succ # 'aa' => 'ab', 'az' => 'ba' end $lomap[mylo] = prefix # the prefix is new, tell tinydns about it $data << ['%'+mylo, prefix] end oldlo, $lo = $lo, mylo yield $lo = oldlo } end def expandip6(ip) # 0102:f::3 => [1, 2, 0, 15, <0..>, 3] ip = '0'+ip if ip[0] == ?: ip = ip+'0' if ip[-1] == ?: ip = ip.split(':') ip[ip.index(''), 1] = ['0'] * (9 - ip.length) if ip.index('') # expand '::' ip.map { |d| d = d.hex ; [d >> 8, d & 255] }.flatten end def arpa(ip, len=4) ip.split('.')[0, len].reverse.join('.') + '.in-addr.arpa' end def arpa6(ip, len=32) expandip6(ip).map { |d| [d >> 4, d & 15] }.flatten[0, len].reverse.map { |e| e.to_s 16 }.join('.') + '.ip6.arpa' end # append suffix if no '.' def s(name) name.include?(?.) ? name : name+$suffix end def generic(fqdn, type, data, ttl=nil, ts=nil, lo=$lo) $data << [':'+fqdn, type, data, ttl, ts, lo] end def ns(zone, dns='a', dnsip='', ttl=nil, ts=nil, lo=$lo) $suffix = '.'+zone if zone !~ /\.arpa$/i $data << ['.'+zone, dnsip, dns, ttl, ts, lo] end def childns(zone, dns='a', dnsip='', ttl=nil, ts=nil, lo=$lo) $data << ['&'+zone, dnsip, dns, ttl, ts, lo] end def host(fqdn, ip, ttl=nil, ts=nil, lo=$lo) $data << ['='+s(fqdn), ip, ttl, ts, lo] end def mx(fqdn, ip, mx='a', dist=0, ttl=nil, ts=nil, lo=$lo) $data << ['@'+s(fqdn), ip, mx, dist, ttl, ts, lo] end def a(fqdn, ip, ttl=nil, ts=nil, lo=$lo) $data << ['+'+s(fqdn), ip, ttl, ts, lo] end def ptr(fqdn, name, ttl=nil, ts=nil, lo=$lo) $data << ['^'+fqdn, s(name), ttl, ts, lo] end def aaaa(fqdn, ip, ttl=nil, ts=nil, lo=$lo) data = expandip6(ip).map { |d| '\\%03o' % d }.join generic(s(fqdn), 28, data, ttl, ts, lo) end def host6(fqdn, ip, ttl=nil, ts=nil, lo=$lo) aaaa s(fqdn), ip, ttl, ts, lo ptr arpa6(ip), s(fqdn), ttl, ts, lo end }