#!/usr/bin/env ruby require 'set' require 'socket' require 'net/dns' require 'net/dns/packet' ### Config ### domain = 'mesh.ffhl' port = 53 ttl = 600 ns = ['mesh.ffhl. 3600 IN NS paul.ffhl.'] soa = 'mesh.ffhl. 0 IN SOA paul.ffhl. freifunk\.luebeck.asta.uni-luebeck.de. 1 3600 180 600 60' ### Config end ### # Fix bugs and hack FQDN validation :> module Net module DNS class RR class SOA def build_pack @soa_pack = pack_name(@mname) @soa_pack += pack_name(@rname) @soa_pack += [@serial,@refresh,@retry,@expire,@minimum].pack("N5") @rdlength = @soa_pack.size end end end module Names def valid?(name) return true end end end end run = true sock = UDPSocket.new Socket::AF_INET6 sock.setsockopt Socket::Option.bool(:INET6, :IPV6, :V6ONLY, false) sock.setsockopt Socket::Option.bool(:INET, :IP, :PKTINFO, true) sock.setsockopt Socket::Option.bool(:INET6, :IPV6, :RECVPKTINFO, true) sock.bind('::', port) while run do data, sendaddr, rflags, *controls = sock.recvmsg Thread.new(data, sendaddr, controls) do |data, sendaddr, controls| pktinfo = nil controls.each do |c| pktinfo = c if c.cmsg_is?(:IP, :PKTINFO) or c.cmsg_is?(:IPV6, :PKTINFO) end return if pktinfo.nil? packet = Net::DNS::Packet::parse(data) return unless packet.header.opCode == Net::DNS::Header::QUERY return unless packet.header.query? packet.header.qr = 1 packet.header.aa = 1 packet.header.tc = 0 packet.header.ra = 0 packet.header.cd = 0 packet.header.ad = 0 packet.header.rCode = Net::DNS::Header::RCode::NOERROR packet.question.each do |q| next unless q.qClass.to_i == Net::DNS::IN host, qdomain = q.qName.split('.', 2) next unless qdomain == domain+'.' begin if q.qType.to_i == Net::DNS::A addresses = Set.new Socket.getaddrinfo(host+'.local.', nil, :INET).each { |addr| addresses << addr[3] } addresses.each do |addr| packet.answer << Net::DNS::RR::A.new(:name => q.qName, :ttl => ttl, :cls => Net::DNS::IN, :type => Net::DNS::A, :address => addr) end elsif q.qType.to_i == Net::DNS::AAAA addresses = Set.new Socket.getaddrinfo(host+'.local.', nil, :INET6).each { |addr| addresses << addr[3] } addresses.each do |addr| packet.answer << Net::DNS::RR::AAAA.new(:name => q.qName, :ttl => ttl, :cls => Net::DNS::IN, :type => Net::DNS::AAAA, :address => addr) end end rescue packet.header.rCode = Net::DNS::Header::RCode::NAME end end if packet.answer.empty? record = Net::DNS::RR::SOA.new(soa) packet.authority = [Net::DNS::RR::SOA.new(:name => record.name, :ttl => record.ttl, :mname => record.mname, :rname => record.rname, :refresh => record.refresh, :retry => record.retry, :expire => record.expire, :minimum => record.minimum, :serial => Time.now.to_i)] else ns.each { |line| packet.authority << Net::DNS::RR::NS.new(line) } end sock.sendmsg(packet.data, 0, sendaddr, pktinfo) end end